Skip to content

Commit cee08ae

Browse files
authored
feat: add Event.list() for listing existing events (#2686)
* feat: add Event.list() classmethod Signed-off-by: threcc <trecchiu@redhat.com> * fix: implement PR comments Signed-off-by: threcc <trecchiu@redhat.com> --------- Signed-off-by: threcc <trecchiu@redhat.com>
1 parent 3de70dd commit cee08ae

1 file changed

Lines changed: 79 additions & 0 deletions

File tree

ocp_resources/event.py

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import warnings
22
from collections.abc import Generator
3+
from datetime import datetime, timedelta, timezone
34
from typing import Any
45

56
from kubernetes.dynamic import DynamicClient
@@ -90,6 +91,84 @@ def get(
9091
timeout=timeout,
9192
)
9293

94+
@staticmethod
95+
def _parse_timestamp(event: Any) -> datetime | None:
96+
"""Parse event timestamp, preferring lastTimestamp over creationTimestamp."""
97+
timestamp = event.get("lastTimestamp") or event.get("metadata", {}).get("creationTimestamp")
98+
if not timestamp:
99+
return None
100+
try:
101+
return datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
102+
except (ValueError, TypeError):
103+
LOGGER.debug(f"Failed to parse event timestamp: {timestamp}")
104+
return None
105+
106+
@classmethod
107+
def list(
108+
cls,
109+
client: DynamicClient,
110+
namespace: str | None = None,
111+
field_selector: str | None = None,
112+
label_selector: str | None = None,
113+
since_seconds: int = 300,
114+
) -> list[Any]:
115+
"""
116+
List existing K8s events using a standard API list call (not watch).
117+
118+
Unlike ``Event.get()`` which uses watch and streams events in real-time,
119+
this method returns already-existing events immediately.
120+
121+
Args:
122+
client: K8s dynamic client.
123+
namespace: Filter events to this namespace.
124+
field_selector: Filter events by fields (e.g. ``"type==Warning"``).
125+
label_selector: Filter events by labels.
126+
since_seconds: Only return events from the last N seconds (default: 300 = 5 minutes).
127+
128+
Returns:
129+
List of event resource objects, sorted by ``lastTimestamp`` descending (most recent first).
130+
131+
Example:
132+
List Warning events from the last 5 minutes in a namespace::
133+
134+
events = Event.list(
135+
client=client,
136+
namespace="my-namespace",
137+
field_selector="type==Warning",
138+
)
139+
"""
140+
if since_seconds < 0:
141+
raise ValueError("since_seconds must be >= 0")
142+
143+
LOGGER.info("Listing events")
144+
LOGGER.debug(
145+
f"list events parameters: namespace={namespace},"
146+
f" field_selector='{field_selector}', label_selector='{label_selector}',"
147+
f" since_seconds={since_seconds}"
148+
)
149+
150+
resource = client.resources.get(api_version=cls.api_version, kind=cls.__name__)
151+
kwargs: dict[str, Any] = {}
152+
if namespace:
153+
kwargs["namespace"] = namespace
154+
if field_selector:
155+
kwargs["field_selector"] = field_selector
156+
if label_selector:
157+
kwargs["label_selector"] = label_selector
158+
159+
response = resource.get(**kwargs)
160+
events = response.items or []
161+
162+
cutoff = datetime.now(tz=timezone.utc) - timedelta(seconds=since_seconds)
163+
timed_events: list[tuple[datetime, Any]] = []
164+
for event in events:
165+
event_time = cls._parse_timestamp(event)
166+
if event_time and event_time >= cutoff:
167+
timed_events.append((event_time, event))
168+
169+
timed_events.sort(key=lambda pair: pair[0], reverse=True)
170+
return [event for _, event in timed_events]
171+
93172
@classmethod
94173
def delete_events(
95174
cls,

0 commit comments

Comments
 (0)