Skip to content

Commit aa3b67e

Browse files
committed
Don't send duplicate notifications for fixed downtimes
1 parent 05de739 commit aa3b67e

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

internal/icinga2/api_responses.go

+6
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,12 @@ type Downtime struct {
104104
// RemoveTime is used to indicate whether a downtime was ended automatically or cancelled prematurely by a user.
105105
// It is set to zero time for the former case, otherwise to the timestamp at which time has been cancelled.
106106
RemoveTime UnixFloat `json:"remove_time"`
107+
108+
// IsFixed is used to differentiate between fixed and flexible downtimes.
109+
// Fixed downtimes always emits a start and triggered event and cause two notifications being sent
110+
// for the very (same) event. Flexible downtimes, on the other hand, only emits a trigger event, and
111+
// don't produce duplicates for the same event.
112+
IsFixed bool `json:"fixed"`
107113
}
108114

109115
// HostServiceRuntimeAttributes are common attributes of both Host and Service objects.

internal/icinga2/api_responses_test.go

+71
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,40 @@ func TestObjectQueriesResult_UnmarshalJSON(t *testing.T) {
131131
Host: "dummy-11",
132132
Author: "icingaadmin",
133133
Comment: "turn down for what",
134+
IsFixed: true,
135+
},
136+
},
137+
},
138+
{
139+
// $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/downtimes' | jq -c '[.results[] | select(.attrs.fixed == false)][1]'
140+
name: "flexible-downtime-host",
141+
jsonData: `{"attrs":{"__name":"dummy-7!691d508b-c93f-4565-819c-3e46ffef1555","active":true,"author":"icingaadmin","authoritative_zone":"","comment":"Flexible","config_owner":"","config_owner_hash":"","duration":7200,"end_time":1714043658,"entry_time":1714040073.241627,"fixed":false,"ha_mode":0,"host_name":"dummy-7","legacy_id":4,"name":"691d508b-c93f-4565-819c-3e46ffef1555","original_attributes":null,"package":"_api","parent":"","paused":false,"remove_time":0,"scheduled_by":"","service_name":"","source_location":{"first_column":0,"first_line":1,"last_column":69,"last_line":1,"path":"/var/lib/icinga2/api/packages/_api/e5ec468f-6d29-4055-9cd4-495dbbef16e3/conf.d/downtimes/dummy-7!691d508b-c93f-4565-819c-3e46ffef1555.conf"},"start_time":1714040058,"templates":["691d508b-c93f-4565-819c-3e46ffef1555"],"trigger_time":1714040073.241627,"triggered_by":"","triggers":[],"type":"Downtime","version":1714040073.241642,"was_cancelled":false,"zone":"master"},"joins":{},"meta":{},"name":"dummy-7!691d508b-c93f-4565-819c-3e46ffef1555","type":"Downtime"}`,
142+
resp: &ObjectQueriesResult[Downtime]{},
143+
expected: &ObjectQueriesResult[Downtime]{
144+
Name: "dummy-7!691d508b-c93f-4565-819c-3e46ffef1555",
145+
Type: "Downtime",
146+
Attrs: Downtime{
147+
Host: "dummy-7",
148+
Author: "icingaadmin",
149+
Comment: "Flexible",
150+
IsFixed: false,
151+
},
152+
},
153+
},
154+
{
155+
// $ curl -k -s -u root:icinga 'https://localhost:5665/v1/objects/downtimes' | jq -c '[.results[] | select(.attrs.fixed == false)][0]'
156+
name: "flexible-downtime-service",
157+
jsonData: `{"attrs":{"__name":"docker-master!disk /!97078a44-8902-495a-9f2a-c1f6802bc63d","active":true,"author":"icingaadmin","authoritative_zone":"","comment":"Flexible","config_owner":"","config_owner_hash":"","duration":7200,"end_time":1714042731,"entry_time":1714039143.459298,"fixed":false,"ha_mode":0,"host_name":"docker-master","legacy_id":3,"name":"97078a44-8902-495a-9f2a-c1f6802bc63d","original_attributes":null,"package":"_api","parent":"","paused":false,"remove_time":0,"scheduled_by":"","service_name":"disk /","source_location":{"first_column":0,"first_line":1,"last_column":69,"last_line":1,"path":"/var/lib/icinga2/api/packages/_api/e5ec468f-6d29-4055-9cd4-495dbbef16e3/conf.d/downtimes/docker-master!disk %2F!97078a44-8902-495a-9f2a-c1f6802bc63d.conf"},"start_time":1714039131,"templates":["97078a44-8902-495a-9f2a-c1f6802bc63d"],"trigger_time":1714039143.459298,"triggered_by":"","triggers":[],"type":"Downtime","version":1714039143.459324,"was_cancelled":false,"zone":""},"joins":{},"meta":{},"name":"docker-master!disk /!97078a44-8902-495a-9f2a-c1f6802bc63d","type":"Downtime"}`,
158+
resp: &ObjectQueriesResult[Downtime]{},
159+
expected: &ObjectQueriesResult[Downtime]{
160+
Name: "docker-master!disk /!97078a44-8902-495a-9f2a-c1f6802bc63d",
161+
Type: "Downtime",
162+
Attrs: Downtime{
163+
Host: "docker-master",
164+
Service: "disk /",
165+
Author: "icingaadmin",
166+
Comment: "Flexible",
167+
IsFixed: false,
134168
},
135169
},
136170
},
@@ -147,6 +181,7 @@ func TestObjectQueriesResult_UnmarshalJSON(t *testing.T) {
147181
Service: "load",
148182
Author: "icingaadmin",
149183
Comment: "Scheduled downtime for backup",
184+
IsFixed: true,
150185
},
151186
},
152187
},
@@ -419,6 +454,7 @@ func TestApiResponseUnmarshal(t *testing.T) {
419454
Host: "dummy-157",
420455
Author: "icingaadmin",
421456
Comment: "updates",
457+
IsFixed: true,
422458
},
423459
},
424460
},
@@ -432,6 +468,7 @@ func TestApiResponseUnmarshal(t *testing.T) {
432468
Service: "http",
433469
Author: "icingaadmin",
434470
Comment: "broken until Monday",
471+
IsFixed: true,
435472
},
436473
},
437474
},
@@ -444,6 +481,7 @@ func TestApiResponseUnmarshal(t *testing.T) {
444481
Host: "dummy-157",
445482
Author: "icingaadmin",
446483
Comment: "updates",
484+
IsFixed: true,
447485
},
448486
},
449487
},
@@ -457,6 +495,7 @@ func TestApiResponseUnmarshal(t *testing.T) {
457495
Service: "http",
458496
Author: "icingaadmin",
459497
Comment: "broken until Monday",
498+
IsFixed: true,
460499
},
461500
},
462501
},
@@ -469,6 +508,20 @@ func TestApiResponseUnmarshal(t *testing.T) {
469508
Host: "dummy-157",
470509
Author: "icingaadmin",
471510
Comment: "updates",
511+
IsFixed: true,
512+
},
513+
},
514+
},
515+
{
516+
name: "flexible-downtimetriggered-host",
517+
jsonData: `{"downtime":{"__name":"dummy-7!691d508b-c93f-4565-819c-3e46ffef1555","author":"icingaadmin","authoritative_zone":"","comment":"Flexible","config_owner":"","config_owner_hash":"","duration":7200,"end_time":1714043658,"entry_time":1714040073.241627,"fixed":false,"host_name":"dummy-7","legacy_id":4,"name":"691d508b-c93f-4565-819c-3e46ffef1555","package":"_api","parent":"","remove_time":0,"scheduled_by":"","service_name":"","source_location":{"first_column":0,"first_line":1,"last_column":69,"last_line":1,"path":"/var/lib/icinga2/api/packages/_api/e5ec468f-6d29-4055-9cd4-495dbbef16e3/conf.d/downtimes/dummy-7!691d508b-c93f-4565-819c-3e46ffef1555.conf"},"start_time":1714040058,"templates":["691d508b-c93f-4565-819c-3e46ffef1555"],"trigger_time":0,"triggered_by":"","triggers":[],"type":"Downtime","version":1714040073.241642,"zone":"master"},"timestamp":1714040073.242575,"type":"DowntimeAdded"}`,
518+
expected: &DowntimeTriggered{
519+
Timestamp: UnixFloat(time.UnixMicro(1714040073242575)),
520+
Downtime: Downtime{
521+
Host: "dummy-7",
522+
Author: "icingaadmin",
523+
Comment: "Flexible",
524+
IsFixed: false,
472525
},
473526
},
474527
},
@@ -482,6 +535,21 @@ func TestApiResponseUnmarshal(t *testing.T) {
482535
Service: "http",
483536
Author: "icingaadmin",
484537
Comment: "broken until Monday",
538+
IsFixed: true,
539+
},
540+
},
541+
},
542+
{
543+
name: "flexible-downtimetriggered-service",
544+
jsonData: `{"downtime":{"__name":"docker-master!disk /!97078a44-8902-495a-9f2a-c1f6802bc63d","author":"icingaadmin","authoritative_zone":"","comment":"Flexible","config_owner":"","config_owner_hash":"","duration":7200,"end_time":1714042731,"entry_time":1714039143.459298,"fixed":false,"host_name":"docker-master","legacy_id":3,"name":"97078a44-8902-495a-9f2a-c1f6802bc63d","package":"_api","parent":"","remove_time":0,"scheduled_by":"","service_name":"disk /","source_location":{"first_column":0,"first_line":1,"last_column":69,"last_line":1,"path":"/var/lib/icinga2/api/packages/_api/e5ec468f-6d29-4055-9cd4-495dbbef16e3/conf.d/downtimes/docker-master!disk %2F!97078a44-8902-495a-9f2a-c1f6802bc63d.conf"},"start_time":1714039131,"templates":["97078a44-8902-495a-9f2a-c1f6802bc63d"],"trigger_time":1714039143.459298,"triggered_by":"","triggers":[],"type":"Downtime","version":1714039143.459324,"zone":""},"timestamp":1714039143.460918,"type":"DowntimeTriggered"}`,
545+
expected: &DowntimeTriggered{
546+
Timestamp: UnixFloat(time.UnixMicro(1714039143460918)),
547+
Downtime: Downtime{
548+
Host: "docker-master",
549+
Service: "disk /",
550+
Author: "icingaadmin",
551+
Comment: "Flexible",
552+
IsFixed: false,
485553
},
486554
},
487555
},
@@ -495,6 +563,7 @@ func TestApiResponseUnmarshal(t *testing.T) {
495563
Author: "icingaadmin",
496564
Comment: "updates",
497565
RemoveTime: UnixFloat(time.Time{}),
566+
IsFixed: true,
498567
},
499568
},
500569
},
@@ -508,6 +577,7 @@ func TestApiResponseUnmarshal(t *testing.T) {
508577
Author: "icingaadmin",
509578
Comment: "updates",
510579
RemoveTime: UnixFloat(time.UnixMicro(1697207096187718)),
580+
IsFixed: true,
511581
},
512582
},
513583
},
@@ -522,6 +592,7 @@ func TestApiResponseUnmarshal(t *testing.T) {
522592
Author: "icingaadmin",
523593
Comment: "broken until Monday",
524594
RemoveTime: UnixFloat(time.UnixMicro(1697207144746117)),
595+
IsFixed: true,
525596
},
526597
},
527598
},

internal/icinga2/client_api.go

+8
Original file line numberDiff line numberDiff line change
@@ -449,9 +449,17 @@ func (client *Client) listenEventStream() error {
449449
ev, err = client.buildDowntimeEvent(client.Ctx, respT.Downtime, false)
450450
evTime = respT.Timestamp.Time()
451451
case *DowntimeStarted:
452+
if !respT.Downtime.IsFixed {
453+
continue
454+
}
455+
452456
ev, err = client.buildDowntimeEvent(client.Ctx, respT.Downtime, true)
453457
evTime = respT.Timestamp.Time()
454458
case *DowntimeTriggered:
459+
if respT.Downtime.IsFixed {
460+
continue
461+
}
462+
455463
ev, err = client.buildDowntimeEvent(client.Ctx, respT.Downtime, true)
456464
evTime = respT.Timestamp.Time()
457465
case *Flapping:

0 commit comments

Comments
 (0)