Skip to content

Commit ff48d7a

Browse files
Merge pull request #31021 from neisw/OCPBUGS-63307-annotation-timestamps
OCPBUGS-63307: honor firstTimestamp annotation value
2 parents a3ffcaf + 0047cd7 commit ff48d7a

2 files changed

Lines changed: 89 additions & 1 deletion

File tree

pkg/monitortestlibrary/pathologicaleventlibrary/duplicated_event_patterns.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1009,9 +1009,19 @@ func (ade *OverlapOtherIntervalsPathologicalEventMatcher) Allows(i monitorapi.In
10091009
return false
10101010
}
10111011

1012+
// Pathological event intervals set From to LastTimestamp (the most recent occurrence),
1013+
// but the event may have first fired much earlier. Use firstTimestamp from the
1014+
// annotations when available so the overlap check covers the full span of the event.
1015+
eventFrom := i.From
1016+
if ft, ok := i.Message.Annotations["firstTimestamp"]; ok {
1017+
if parsed, err := time.Parse(time.RFC3339, ft); err == nil {
1018+
eventFrom = parsed
1019+
}
1020+
}
1021+
10121022
// Match the pathological event if it overlaps with any of the given set of intervals.
10131023
for _, nui := range ade.allowIfWithinIntervals {
1014-
if nui.From.Before(i.From) && nui.To.After(i.To) {
1024+
if nui.From.Before(eventFrom) && nui.To.After(i.To) {
10151025
logrus.Infof("%s was found to overlap with %s, ignoring pathological event as they fall within range of specified intervals", i, nui)
10161026
return true
10171027
}

pkg/monitortestlibrary/pathologicaleventlibrary/duplicated_events_special_test.go

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,90 @@
11
package pathologicaleventlibrary
22

33
import (
4+
"fmt"
5+
"regexp"
46
"testing"
7+
"time"
58

9+
v1 "github.com/openshift/api/config/v1"
610
"github.com/openshift/origin/pkg/monitor/monitorapi"
711
"github.com/stretchr/testify/assert"
812
)
913

14+
func Test_OverlapMatcherUsesFirstTimestamp(t *testing.T) {
15+
// Simulate the real-world scenario: an event fires 23 times over 90 minutes.
16+
// The interval's From is set to LastTimestamp (the final occurrence), but
17+
// firstTimestamp in annotations records when the event actually started.
18+
testStart := time.Date(2026, 4, 10, 12, 0, 0, 0, time.UTC)
19+
firstTimestamp := testStart.Add(15 * time.Minute) // 12:15
20+
lastTimestamp := testStart.Add(105 * time.Minute) // 13:45
21+
testEnd := testStart.Add(110 * time.Minute) // 13:50
22+
23+
// The "test interval" that the event should overlap with (12:00 - 13:50).
24+
testInterval := monitorapi.NewInterval(monitorapi.SourceE2ETest, monitorapi.Info).
25+
Locator(monitorapi.NewLocator().NodeFromName("test")).
26+
Message(monitorapi.NewMessage().HumanMessage("test interval")).
27+
Build(testStart, testEnd)
28+
29+
// Build a pathological event interval the way watchevents/event.go does:
30+
// From = lastTimestamp, To = lastTimestamp + 1s, firstTimestamp in annotations.
31+
pathologicalInterval := monitorapi.NewInterval(monitorapi.SourceKubeEvent, monitorapi.Warning).
32+
Locator(monitorapi.NewLocator().PodFromNames("openshift-test", "test-pod", "")).
33+
Message(
34+
monitorapi.NewMessage().
35+
Reason("TestReason").
36+
HumanMessage("test pathological event").
37+
WithAnnotation(monitorapi.AnnotationCount, fmt.Sprintf("%d", 23)).
38+
WithAnnotation("firstTimestamp", firstTimestamp.Format(time.RFC3339)).
39+
WithAnnotation("lastTimestamp", lastTimestamp.Format(time.RFC3339))).
40+
Build(lastTimestamp, lastTimestamp.Add(1*time.Second))
41+
42+
matcher := &OverlapOtherIntervalsPathologicalEventMatcher{
43+
delegate: &SimplePathologicalEventMatcher{
44+
name: "TestMatcher",
45+
messageReasonRegex: regexp.MustCompile(`^TestReason$`),
46+
},
47+
allowIfWithinIntervals: monitorapi.Intervals{testInterval},
48+
}
49+
50+
// Should be allowed because firstTimestamp (12:15) falls within the test interval (12:00-13:50).
51+
assert.True(t, matcher.Allows(pathologicalInterval, v1.HighlyAvailableTopologyMode),
52+
"event should be allowed when firstTimestamp falls within the overlap interval")
53+
54+
// Now test with a test interval that ends before lastTimestamp but after firstTimestamp.
55+
// The event's firstTimestamp (12:15) is within [12:00, 13:00], and To (13:45:01) is NOT.
56+
shorterTestInterval := monitorapi.NewInterval(monitorapi.SourceE2ETest, monitorapi.Info).
57+
Locator(monitorapi.NewLocator().NodeFromName("test")).
58+
Message(monitorapi.NewMessage().HumanMessage("short test interval")).
59+
Build(testStart, testStart.Add(60*time.Minute)) // 12:00 - 13:00
60+
61+
matcherShort := &OverlapOtherIntervalsPathologicalEventMatcher{
62+
delegate: &SimplePathologicalEventMatcher{
63+
name: "TestMatcher",
64+
messageReasonRegex: regexp.MustCompile(`^TestReason$`),
65+
},
66+
allowIfWithinIntervals: monitorapi.Intervals{shorterTestInterval},
67+
}
68+
69+
// Should NOT be allowed because the event's To (13:45:01) extends past the test interval's end (13:00).
70+
assert.False(t, matcherShort.Allows(pathologicalInterval, v1.HighlyAvailableTopologyMode),
71+
"event should not be allowed when its To extends beyond the overlap interval")
72+
73+
// Test without firstTimestamp annotation — should fall back to From (lastTimestamp).
74+
noAnnotationInterval := monitorapi.NewInterval(monitorapi.SourceKubeEvent, monitorapi.Warning).
75+
Locator(monitorapi.NewLocator().PodFromNames("openshift-test", "test-pod", "")).
76+
Message(
77+
monitorapi.NewMessage().
78+
Reason("TestReason").
79+
HumanMessage("test pathological event").
80+
WithAnnotation(monitorapi.AnnotationCount, fmt.Sprintf("%d", 23))).
81+
Build(lastTimestamp, lastTimestamp.Add(1*time.Second))
82+
83+
// Without firstTimestamp, From is lastTimestamp (13:45). The test interval [12:00, 13:50] contains it.
84+
assert.True(t, matcher.Allows(noAnnotationInterval, v1.HighlyAvailableTopologyMode),
85+
"event without firstTimestamp should fall back to From for overlap check")
86+
}
87+
1088
func Test_singleEventThresholdCheck_getNamespacedFailuresAndFlakes(t *testing.T) {
1189
namespace := "openshift-etcd-operator"
1290
samplePod := "etcd-operator-6f9b4d9d4f-4q9q8"

0 commit comments

Comments
 (0)