Skip to content

feat: add events viewer for cluster events#3239

Open
eggfoobar wants to merge 2 commits intoopenshift:mainfrom
eggfoobar:add-cluster-events-html
Open

feat: add events viewer for cluster events#3239
eggfoobar wants to merge 2 commits intoopenshift:mainfrom
eggfoobar:add-cluster-events-html

Conversation

@eggfoobar
Copy link
Contributor

@eggfoobar eggfoobar commented Feb 4, 2026

added ability to consume the events.json collected from gather-extra of a job run

sippy-events

Summary by CodeRabbit

  • New Features
    • Added Kubernetes events viewer for job runs with an interactive, filterable table and dedicated route.
    • New backend endpoint powering the Events view to load event data for a job run.
    • Time-range filtering (UTC) and multi-criteria filters: Kind, Namespace, Name, Type, Reason, Message.
    • Sortable columns, dynamic column visibility, and summary counts (Total, Filtered, Warnings).
    • New navigation link from the Intervals view to the Events view; clear loading, empty, and error states.

@openshift-ci-robot
Copy link

Pipeline controller notification
This repo is configured to use the pipeline controller. Second-stage tests will be triggered either automatically or after lgtm label is added, depending on the repository configuration. The pipeline controller will automatically detect which contexts are required and will utilize /test Prow commands to trigger the second stage.

For optional jobs, comment /test ? to see a list of all defined jobs. To trigger manually all jobs from second stage use /pipeline required command.

This repository is configured in: automatic mode

@openshift-ci openshift-ci bot requested a review from deads2k February 4, 2026 21:45
@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 4, 2026

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: eggfoobar
Once this PR has been reviewed and has the lgtm label, please assign deepsm007 for approval. For more information see the Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-ci openshift-ci bot requested a review from sosiouxme February 4, 2026 21:45
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 4, 2026

Walkthrough

Adds backend logic and an HTTP endpoint to fetch and normalize Kubernetes events.json for a job run from GCS, plus a new frontend EventsChart component, route, and link to view those events.

Changes

Cohort / File(s) Summary
Backend: job run events logic
pkg/api/jobrunevents/job_run_events.go
New file/package that locates events.json in GCS (with DB-based fallback), fetches and unmarshals it, flattens raw kube events into exported KubeEvent, and returns EventListResponse. Adds logging and error handling.
Backend: HTTP handler wiring
pkg/sippyserver/server.go
New handler jsonJobRunEvents registered at /api/jobs/runs/events, validates params, derives GCS path when needed, delegates to jobrunevents.JobRunEvents, and adds the package import.
Frontend: Events page & component
sippy-ng/src/prow_job_runs/EventsChart.js
New React component that fetches events, auto-derives time range, provides UTC time-range controls, multi-field filters, sortable columns, column visibility toggles, summary counts, and navigation link. Declares propTypes.
Frontend: routing & integration
sippy-ng/src/App.js, sippy-ng/src/prow_job_runs/IntervalsChart.js
Adds route /job_runs/:jobrunid/:jobname?/:repoinfo?/:pullnumber?/events, an EventsChart wrapper, and a "View Cluster Events" link in IntervalsChart built from route params.

Sequence Diagram

sequenceDiagram
    actor User
    participant Frontend as Frontend (React)
    participant Server as Backend (HTTP)
    participant DB as Database
    participant GCS as GCS Storage

    User->>Frontend: Navigate to Events page
    Frontend->>Server: GET /api/jobs/runs/events (jobRunID, jobName, repoInfo, pullNumber)
    Server->>DB: Fetch job run record (artifact path / URL override)
    DB-->>Server: Job run entry (may include GCS path / URL override)
    Server->>GCS: Locate artifact via regex & fetch events.json
    GCS-->>Server: Return events.json
    Server->>Server: Unmarshal JSON, flatten to KubeEvent[], build EventListResponse
    Server-->>Frontend: 200 OK + EventListResponse
    Frontend->>Frontend: Apply filters/sorting and render table
    Frontend-->>User: Display interactive events table
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 3
❌ Failed checks (3 warnings)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Excessive Css In React Should Use Styles ⚠️ Warning EventsChart component has excessive inline styling with repeated flex layout patterns (4 properties) and complex conditional TableCell styling that should use useStyles. Extract repeated flex patterns into useStyles classes and move complex conditional TableCell styling logic into useStyles with computed class names.
Single Responsibility And Clear Naming ⚠️ Warning EventsChart component violates SRP with 15+ state variables and mixed responsibilities across fetching, filtering (6+ types), sorting, calculations, and UI management. Extract filter/sort state into custom hooks, create FilterPanel sub-component, simplify prop handling to reduce complexity below SRP threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The pull request title 'feat: add events viewer for cluster events' accurately describes the main change: a new events viewer UI for displaying cluster events collected from job runs.
Go Error Handling ✅ Passed Go error handling follows proper patterns with explicit if err != nil checks, nil pointer checks, proper logging with context, no silent errors, and graceful handling of missing resources.
Sql Injection Prevention ✅ Passed New jobrunevents package and API endpoint analyzed. No SQL injection vulnerabilities found; code uses GORM ORM with proper parameterization and validates jobRunID before use.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@sippy-ng/src/prow_job_runs/EventsChart.js`:
- Around line 297-301: The current render uses <LaunderedLink
address={jobRunUrl}> which throws when jobRunUrl is empty; update EventsChart.js
to guard that usage by checking jobRunUrl before rendering LaunderedLink (e.g.,
if jobRunUrl is falsy render plain text "GCS job run" or a non-link fallback
inside the same Typography), so the code path that references LaunderedLink only
runs when jobRunUrl is a non-empty, valid URL; modify the JSX around the
Typography block that currently uses jobRunUrl to conditionally render the link
component.

In `@sippy-ng/src/prow_job_runs/IntervalsChart.js`:
- Around line 572-577: Move the useParams() call out of the render-after-returns
zone and to the top of the IntervalsChart component alongside the other hooks
(i.e., where other useState/useEffect calls live), so hooks are invoked
unconditionally; then either compute eventsPath after the early-return checks
inside the render body or compute it at the top using a useMemo that depends on
the params (keep references to useParams and eventsPath intact), ensuring hook
order doesn’t change between renders.
🧹 Nitpick comments (3)
pkg/api/jobrunevents/job_run_events.go (1)

57-76: Consider accepting a context parameter for cancellation support.

The function uses context.TODO() on line 92 when calling gcsJobRun.GetContent(). For consistency with other API handlers and to support request cancellation/timeouts, consider accepting a context.Context parameter.

♻️ Proposed signature change
-func JobRunEvents(gcsClient *storage.Client, dbc *db.DB, jobRunID int64, gcsBucket, gcsPath string, logger *log.Entry) (*EventListResponse, error) {
+func JobRunEvents(ctx context.Context, gcsClient *storage.Client, dbc *db.DB, jobRunID int64, gcsBucket, gcsPath string, logger *log.Entry) (*EventListResponse, error) {

Then update line 92:

-	content, err := gcsJobRun.GetContent(context.TODO(), eventsPath)
+	content, err := gcsJobRun.GetContent(ctx, eventsPath)
pkg/sippyserver/server.go (1)

1428-1475: Consider extracting duplicated GCS path construction logic.

The GCS path construction logic (lines 1454-1465) is duplicated from jsonJobRunIntervals (lines 1399-1417). Consider extracting this into a shared helper function to reduce duplication and ensure consistent behavior.

♻️ Example helper extraction
// buildJobRunGCSPath constructs a GCS path from job run parameters
func buildJobRunGCSPath(jobRunIDStr, jobName, repoInfo, pullNumber string) string {
	if len(jobName) == 0 {
		return ""
	}
	if len(repoInfo) > 0 {
		if repoInfo == "openshift_origin" {
			return fmt.Sprintf("pr-logs/pull/%s/%s/%s", pullNumber, jobName, jobRunIDStr)
		}
		return fmt.Sprintf("pr-logs/pull/%s/%s/%s/%s", repoInfo, pullNumber, jobName, jobRunIDStr)
	}
	return fmt.Sprintf("logs/%s/%s", jobName, jobRunIDStr)
}
sippy-ng/src/prow_job_runs/EventsChart.js (1)

84-88: Redundant parameter extraction from both useParams() and props.

The component extracts route parameters via both useParams() (line 86) and props (line 87). The props come from the EventsChartWrapper in App.js which itself uses useParams(). This creates confusion about which source should be used.

Consider using only props (which are passed by the wrapper) and removing the useParams() call, or vice versa. Currently, useParams values are used for the intervals link (line 292) while props are used for API calls (lines 111-114).

♻️ Proposed simplification - use only props
 export default function EventsChart(props) {
   const classes = useStyles()
-  const { jobrunid, jobname, repoinfo, pullnumber } = useParams()
   const { jobRunID, jobName, repoInfo, pullNumber } = props

Then update line 292:

-          to={buildIntervalsPath(jobrunid, jobname, repoinfo, pullnumber)}
+          to={buildIntervalsPath(jobRunID, jobName, repoInfo, pullNumber)}

And update buildIntervalsPath to handle the prop names (they use different casing).

@eggfoobar eggfoobar force-pushed the add-cluster-events-html branch from f562700 to fb423ef Compare February 5, 2026 02:49
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@sippy-ng/src/prow_job_runs/EventsChart.js`:
- Around line 86-115: The component inconsistently uses route params
(useParams() / jobrunid, jobname, repoinfo, pullnumber) for links while using
props (jobRunID, jobName, repoInfo, pullNumber) for fetching, causing undefined
links when props are provided; fix by computing single “effective” values (e.g.,
const effectiveJobRunID = jobRunID || jobrunid, effectiveJobName = jobName ||
jobname, etc.) once at top of EventsChart and then use those effective*
variables everywhere—including inside fetchData URL construction and when
building the Intervals link—so both fetch and link paths come from the same
source (reference symbols: useParams, jobrunid, jobname, repoinfo, pullnumber,
jobRunID, jobName, repoInfo, pullNumber, fetchData).

@openshift-ci-robot
Copy link

Scheduling required tests:
/test e2e

added ability to consume the events.json collected from gather-extra of a job run

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: ehila <ehila@redhat.com>
@eggfoobar eggfoobar force-pushed the add-cluster-events-html branch from fb423ef to e991678 Compare February 5, 2026 05:14
@openshift-ci-robot
Copy link

Scheduling required tests:
/test e2e

@petr-muller
Copy link
Member

/cc

@openshift-ci openshift-ci bot requested a review from petr-muller February 5, 2026 13:25
@dgoodwin
Copy link
Contributor

dgoodwin commented Feb 5, 2026

Whoah this looks cool. Are the filters linkable in bugs and such?

@eggfoobar
Copy link
Contributor Author

Oh, that's such a great idea, let me add that in, it's super useful!

added support to link specific event filters

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: ehila <ehila@redhat.com>
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@sippy-ng/src/prow_job_runs/EventsChart.js`:
- Around line 166-173: The error/loading messages currently interpolate jobRunID
and jobName which can be undefined when route params are used; update message
construction to use effectiveJobRunID and effectiveJobName instead. Locate calls
to setFetchError and any loading/error messages (e.g., the setFetchError call
shown and the messages around lines 304-306) and replace jobRunID/jobName with
effectiveJobRunID/effectiveJobName so the displayed text matches the actual
fetch parameters; ensure any setIsLoading or other status messages use the same
effective* variables for consistency.
- Around line 274-291: clearFilters currently only resets timeFrom/timeTo when
allEvents has timestamps, leaving stale values when allEvents is empty; update
clearFilters (function) to explicitly clear the time range in the else case by
calling setTimeFrom and setTimeTo with the “cleared” value your component
expects (e.g. empty string or null) so time filters are reset even when
allEvents.length === 0; ensure you still compute min/max and call
formatDateTimeLocalUTC(min/max) when timestamps exist.

@openshift-ci-robot
Copy link

Scheduling required tests:
/test e2e

@openshift-ci
Copy link
Contributor

openshift-ci bot commented Feb 6, 2026

@eggfoobar: all tests passed!

Full PR test history. Your PR dashboard.

Details

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository. I understand the commands that are listed here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants