Skip to content

feat(evalhub): emit Kubernetes events for operator-detected evaluation failures (RHAI-278) - #846

Merged
ruivieira merged 9 commits into
mainfrom
dev/RHAI-278
Aug 6, 2026
Merged

feat(evalhub): emit Kubernetes events for operator-detected evaluation failures (RHAI-278)#846
ruivieira merged 9 commits into
mainfrom
dev/RHAI-278

Conversation

@ruivieira

@ruivieira ruivieira commented Aug 1, 2026

Copy link
Copy Markdown
Member

What and why

EvalHub evaluation jobs can fail in ways the EvalHub server cannot self-report OOM kills, image pull errors, and Kueue admission failures all happen before or outside the server's callback path. This PR wires Kubernetes event emission into both failure reconcilers so these infrastructure failures are observable via kubectl describe job / kubectl get events, completing the failure signal chain for RHAI-278.

Note: This PR is dependent on #843, which must be merged first.

Closes RHOAIENG-80112, RHOAIENG-80113, RHOAIENG-80114.

Type

  • feat
  • fix
  • docs
  • refactor / chore
  • test / ci

Testing

  • Tests added or updated
  • Tested manually

Lifecycle unit tests use fake.Client, record.FakeRecorder, and a local httptest.Server to exercise the full Reconcile() path. Cases covered:

  • Dedup — server already handled: evaluation-phase=Failed label already set by EvalHub server → operator returns early, no duplicate event
  • OOM kill: adapter container terminated with OOMKilledEvaluationFailed warning event emitted + evaluation-phase=Failed label + evaluation-status annotation stamped on Job
  • Image pull error: init container stuck on ErrImagePull → same lifecycle
  • Kueue eviction: Workload with QuotaReserved=False / InadmissibleEvaluationFailed warning event + Job label patch + Workload annotated as reported

Changes

  • RBAC (RHOAIENG-80112): add events:create/patch and jobs:get/patch permissions; wire EventRecorder into both failure reconciler constructors via mgr.GetEventRecorderFor
  • Event emission (RHOAIENG-80113): emit Warning / EvaluationFailed after a successful POST to EvalHub; patch evaluation-phase=Failed and evaluation-status on the Job; Kueue path also annotates the Workload as reported
  • Tests (RHOAIENG-80114): lifecycle unit tests for both reconcilers covering the four failure scenarios above

Summary by CodeRabbit

  • New Features

    • Added clearer Kubernetes warning events for evaluation failures.
    • Evaluation failures now update associated Jobs with failed status details.
    • Added permissions required to record events and update Jobs.
  • Bug Fixes

    • Prevented duplicate handling of failures already reported to EvalHub.
    • Improved handling of admission failures, out-of-memory errors, and image-pull failures.
    • Failed Jobs are cleaned up after successful synchronization.
  • Tests

    • Added coverage for failure reporting, event emission, status updates, deduplication, and cleanup.

…lHub (#842)

* chore(rbac): add events:create and jobs:patch/get permissions for EvalHub ServiceAccount

Add two new ClusterRoles for the EvalHub ServiceAccount:
- evalhub-events: grants events create, so the EvalHub server can emit
  Kubernetes Events against backing Job resources on evaluation lifecycle
  transitions (EvaluationStarted, EvaluationCompleted, EvaluationFailed,
  EvaluationThresholdViolated)
- evalhub-jobs-writer extended with get and patch verbs, so the server can
  read-modify-patch the trustyai.opendatahub.io/evaluation-phase label on
  running Jobs

Both new ClusterRoleBindings are added to the OPA policy allowlist.
No functional code changes; this is the RBAC prerequisite for RHAI-277.

* fix(rbac): add patch verb to evalhub-events ClusterRole for EventRecorder deduplication
* feat(evalhub): emit events for job infrastructure failures

Patch evaluation-phase=Failed label and evaluation-status annotation on
Job resources. Include deduplication logic to skip event emission if the
EvalHub server has already marked the failure.

* fix(evalhub): emit EvaluationFailed event only after successful EvalHub POST
…emission (RHOAIENG-80114) (#845)

* feat(evalhub): emit events for job infrastructure failures

Patch evaluation-phase=Failed label and evaluation-status annotation on
Job resources. Include deduplication logic to skip event emission if the
EvalHub server has already marked the failure.

* fix(evalhub): emit EvaluationFailed event only after successful EvalHub POST

* test(evalhub): add lifecycle unit tests for failure reconciler event emission (RHOAIENG-80114)

Cover the full Reconcile() path for EvalHubEvaluationJobFailureReconciler and
EvalHubEvaluationFailedKueueWorkloadsReconciler using fake.Client and
record.FakeRecorder. Tests use a local httptest.Server to absorb EvalHub
POST calls and an interceptor to capture the evaluation-phase=Failed label
patch before job deletion.

Cases added:
- dedup: server already set evaluation-phase=Failed → no operator event
- OOM-killed adapter container → EvaluationFailed event + label patch + job cleanup
- ErrImagePull on init container → EvaluationFailed event + label patch + job cleanup
- Kueue QuotaReserved=Inadmissible → EvaluationFailed event + job label + workload annotation
@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@ruivieira, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 24 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 9119409e-1243-4ea2-968b-7cab6f3b4825

📥 Commits

Reviewing files that changed from the base of the PR and between b51adc3 and 656bcc6.

📒 Files selected for processing (3)
  • config/components/evalhub/rbac/evalhub_events_role.yaml
  • controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go
  • controllers/evalhub/evaluation_job_failure_reconciler.go
📝 Walkthrough

Walkthrough

EvalHub failure reconcilers now emit Kubernetes warning Events, mark failed Jobs, prevent duplicate failure handling, and annotate completed Kueue Workloads. Kustomize and policy RBAC configuration grants the required Event and Job permissions.

Changes

EvalHub failure reporting

Layer / File(s) Summary
RBAC and reconciler wiring
config/components/evalhub/..., controllers/evalhub/..., policy/rbac.rego
The EvalHub component registers Event and Job RBAC resources. Both reconcilers receive an EventRecorder.
Job failure reconciliation
controllers/evalhub/evaluation_job_failure_reconciler.go, controllers/evalhub/evaluation_job_failure_reconciler_lifecycle_test.go
The reconciler skips Jobs already marked failed, emits EvaluationFailed warning Events, patches failure metadata, and validates OOMKilled and ErrImagePull handling.
Kueue workload failure reconciliation
controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go, controllers/evalhub/evaluation_failed_kueue_workloads_reconciler_lifecycle_test.go
The reconciler records failure Events, patches Job metadata, preserves Workload annotation as the completion gate, and validates the lifecycle flow.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant FailedJob
  participant EvalHubFailureReconciler
  participant EvalHub
  participant KubernetesAPI
  FailedJob->>EvalHubFailureReconciler: report detected failure
  EvalHubFailureReconciler->>EvalHub: POST evaluation failure
  EvalHub-->>EvalHubFailureReconciler: successful response
  EvalHubFailureReconciler->>KubernetesAPI: emit EvaluationFailed Event
  EvalHubFailureReconciler->>KubernetesAPI: patch failed Job metadata
Loading

Possibly related PRs

Suggested labels: lgtm

Suggested reviewers: robgeada, abeltramo, julpayne

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: emitting Kubernetes events for operator-detected EvalHub evaluation failures.
Docstring Coverage ✅ Passed Docstring coverage is 90.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev/RHAI-278

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@ruivieira ruivieira self-assigned this Aug 2, 2026
@ruivieira ruivieira added the kind/enhancement New feature or request label Aug 2, 2026
@ruivieira ruivieira moved this to In Review in TrustyAI planning Aug 2, 2026
@ruivieira

Copy link
Copy Markdown
Member Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
controllers/evalhub/evaluation_job_failure_reconciler.go (1)

433-449: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Persist the successful report state before completing reconciliation.

A transient Job patch failure leaves the two reconcilers in inconsistent states. In the Job path, the retry repeats the EvalHub POST and emits another Event because annotationFailurePending remains set. In the Kueue path, the Workload is marked reported even though the Job never receives evaluation-phase=Failed or evaluation-status.

  • controllers/evalhub/evaluation_job_failure_reconciler.go#L433-L449: add a durable post-success state that prevents repeated POSTs and Events when the promotion patch fails.
  • controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go#L338-L345: retry the Job metadata update and do not set annotationKueueFailedWorkloadEventReported until that update succeeds.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@controllers/evalhub/evaluation_job_failure_reconciler.go` around lines 433 -
449, In controllers/evalhub/evaluation_job_failure_reconciler.go:433-449, make
the successful EvalHub report durable before reconciliation completes so a
failed promotion patch prevents repeated POSTs and Events; update the retry path
to recognize that durable state and avoid reposting. In
controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go:338-345,
retry the Job metadata update and set annotationKueueFailedWorkloadEventReported
only after that update succeeds, keeping the Workload state consistent with the
Job.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@controllers/evalhub/evaluation_job_failure_reconciler.go`:
- Around line 433-449: In
controllers/evalhub/evaluation_job_failure_reconciler.go:433-449, make the
successful EvalHub report durable before reconciliation completes so a failed
promotion patch prevents repeated POSTs and Events; update the retry path to
recognize that durable state and avoid reposting. In
controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go:338-345,
retry the Job metadata update and set annotationKueueFailedWorkloadEventReported
only after that update succeeds, keeping the Workload state consistent with the
Job.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e344f6d3-07d6-4a18-ab7d-9b43c0b17c22

📥 Commits

Reviewing files that changed from the base of the PR and between 73073b4 and 42e5771.

📒 Files selected for processing (9)
  • config/components/evalhub/kustomization.yaml
  • config/components/evalhub/rbac/evalhub_events_binding.yaml
  • config/components/evalhub/rbac/evalhub_events_role.yaml
  • config/components/evalhub/rbac/evalhub_jobs_writer_role.yaml
  • controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go
  • controllers/evalhub/evaluation_failed_kueue_workloads_reconciler_lifecycle_test.go
  • controllers/evalhub/evaluation_job_failure_reconciler.go
  • controllers/evalhub/evaluation_job_failure_reconciler_lifecycle_test.go
  • policy/rbac.rego

@sheltoncyril sheltoncyril left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

/lgtm

@sheltoncyril sheltoncyril left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Claude had a few comments

@openshift-ci openshift-ci Bot removed the lgtm label Aug 6, 2026

@sheltoncyril sheltoncyril left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

AI code review (max depth, 10-angle sweep). 3 confirmed bugs, 9 additional findings. See inline comments.

Comment thread controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go
Comment thread controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go
Comment thread controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go
Comment thread controllers/evalhub/evaluation_failed_kueue_workloads_reconciler.go
Comment thread controllers/evalhub/evaluation_job_failure_reconciler.go Outdated
Comment thread controllers/evalhub/evaluation_job_failure_reconciler.go
Comment thread controllers/evalhub/evaluation_job_failure_reconciler.go
Comment thread controllers/evalhub/evaluation_job_failure_reconciler.go
Comment thread config/components/evalhub/rbac/evalhub_events_role.yaml Outdated
Comment thread config/components/evalhub/rbac/evalhub_jobs_writer_role.yaml
Annotate the Workload before emitting the Event and patching Job labels
so that workloadFailedEventAlreadyReported acts as the primary dedup
gate on retry. Previously, if both patchJobFailureLabels and
annotateWorkloadReported failed after a successful POST, the next
reconcile would re-POST to EvalHub and re-emit the Event.
When the Workload annotation succeeds but patchJobFailureLabels fails,
the Job permanently lacks the evaluation-phase and evaluation-status
metadata. Requeue on patchJobFailureLabels failure and add a retry
branch that patches only the Job labels when the Workload annotation
is already present.
The serverAlreadyHandledFailure early-return path skipped Job deletion,
leaving failed Jobs in the namespace indefinitely. Add the same
deleteEvalHubFailureSyncedJob call that the failureAlreadyReported path
already performs.
The role is currently bound to the operator SA but is intended for the
EvalHub server SA once RHAI-277 lands. Update the comment to reflect
the current state and planned rebinding.
ruivieira and others added 2 commits August 6, 2026 18:24
When promotePatch failed, the retry path re-executed the POST to
EvalHub and re-emitted the Kubernetes Event because failurePendingReport
only skipped the pending-annotation write. Move the POST inside the
!failurePendingReport block so retries skip it, and move Eventf after
promotePatch so it only fires once the promote succeeds.
@openshift-ci openshift-ci Bot added the lgtm label Aug 6, 2026
@openshift-ci

openshift-ci Bot commented Aug 6, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: sheltoncyril

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 commented Aug 6, 2026

Copy link
Copy Markdown

@ruivieira: The following test failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/trustyai-service-operator-e2e 656bcc6 link true /test trustyai-service-operator-e2e

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.

@ruivieira
ruivieira merged commit 1710b2b into main Aug 6, 2026
13 of 17 checks passed
@ruivieira
ruivieira deleted the dev/RHAI-278 branch August 6, 2026 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement New feature or request lgtm

Projects

Status: In Review

Development

Successfully merging this pull request may close these issues.

2 participants