Skip to content

fix(validator): fail fast on eval errors; nil-safe health checks - #1261

Merged
yuanchen8911 merged 1 commit into
NVIDIA:mainfrom
yuanchen8911:fix/deployment-health-check-eval-and-nil-safety
Jun 9, 2026
Merged

yuanchen8911 merged 1 commit into
NVIDIA:mainfrom
yuanchen8911:fix/deployment-health-check-eval-and-nil-safety

Conversation

@yuanchen8911

@yuanchen8911 yuanchen8911 commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Three regression fixes for deployment-phase health-check validation, introduced by the recent in-process executor + deepened-check stack (#1235/#1245/#1252):

  1. In-process executor retries permanent eval errors (inprocess.go)
  2. Nil-unsafe container-status expressions (22 health checks)
  3. dynamo-platform check asserts a non-existent Deployment name

Motivation / Context

On an EKS H100 cluster, aicr validate --phase deployment hung ~8 min and returned status=other ("pod not found for Job") instead of real results. Root cause is three interacting issues:

  1. feat(validators): replace chainsaw binary with in-process executor #1252 — runAssertWithRetry / runErrorWithRetry retry on any non-nil error, so a permanent JMESPath evaluation error is retried for the full 6m assert window. The old chainsaw binary treated eval errors as terminal and failed fast.
  2. feat(recipes): deepen 21 chainsaw health checks; close epic #660 #1245 — (init)containerStatuses[?...] | length(@) throws invalid type for: <nil> on any pod without (init) containers (the common case), which feeds defect fix: remove namespaceOverride from nvidia-dra-driver-gpu values #1.
  3. dynamo-platform — validate-deployment-exists asserts a Deployment named dynamo-operator, but the chart prefixes it with the release name (dynamo-platform-dynamo-operator-controller-manager), so the assert never matched and retried to the deadline — a false negative against a healthy component.

(Defects #1/#2 independently confirmed by Nathan.)

Related: #1235, #1245, #1252

Type of Change

  • Bug fix (non-breaking change that fixes an issue)

Component(s) Affected

  • Recipe engine / data (pkg/recipe) — recipes/checks/*
  • Validator (pkg/validator) — validators/chainsaw/inprocess.go

Implementation Notes

  1. Classify assertion-engine errors as ErrCodeInvalidRequest (terminal) and short-circuit both retry loops via a new isTerminalAssertErr helper, so a non-evaluable expression fails fast instead of burning the assert deadline. Transient failures (mismatch, NotFound) still retry. Adds a regression test asserting a terminal eval error returns in < AssertRetryInterval rather than retrying to the deadline.
  2. Coalesce to an empty array — (initContainerStatuses || + "[]" + )[?...] — across all 22 affected component health checks (both initContainerStatuses and containerStatuses).
  3. Match the dynamo-operator manager Deployment by its stable app.kubernetes.io/name=dynamo-operator label (List-and-match) instead of a release-name-dependent hardcoded name.

Scope note (conditions[?...] filters): the remaining (conditions[?type == '...']) filters are intentionally not coalesced — they are projection asserts without | length(@) (so nil .status.conditions yields an empty match, not a <nil> throw) and target CRDs/Deployments that reliably populate .status.conditions. They are not the same throwing class as the length() expressions fixed here.

Testing

golangci-lint run -c .golangci.yaml ./validators/chainsaw/...   # 0 issues
go test ./validators/chainsaw/...                                # ok, coverage 60.7%

New regression test TestRunChainsawTestInProcess_TerminalEvalErrorFailsFast reproduces the exact invalid type for: <nil> throw and asserts fast-fail (returns in 0.00s vs. retrying to deadline).

On-cluster (EKS H100): deployment phase went from an 8m timeout (status=other) to PASSED in ~21s; full run on this branch = deployment 4/4 + conformance 11/11 green. (Performance phase ran a real Qwen3-8B benchmark and reports a true TTFT-p99 SLA miss — a separate cluster/SLA matter, not this change.) Full make qualify not run locally — recommend CI / a maintainer run before merge.

Risk Assessment

  • Low — Data/expression fixes plus a localized executor error-classification change; no API or schema changes, easy to revert.

Rollout notes: Reclassifying assertion-engine errors ErrCodeInternal → ErrCodeInvalidRequest is a caller-visible semantic shift (CLI exit 8→2, HTTP 500→400) for a malformed bundled-registry expression — intentional and anticipated by the design comment; backwards compatible otherwise.

Checklist

  • Linter passes (golangci-lint on changed package — 0 issues)
  • Tests pass locally (go test ./validators/chainsaw/...), incl. new regression test
  • Full make qualify (recommend running in CI / before merge)
  • I did not skip/disable tests to make CI green
  • I added a regression test for the terminal-eval-error fast-fail
  • Changes follow existing patterns in the codebase
  • Commits are cryptographically signed (git commit -S)

@coderabbitai

coderabbitai Bot commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This PR updates many Kyverno/Chainsaw health-check YAMLs to treat missing Pod status arrays as empty lists before JMESPath waiting-reason filters, changes the dynamo-platform health-check to select the operator by label, and refactors the in-process Chainsaw validator to classify assertion/evaluation failures as ErrCodeInvalidRequest and fast-fail retry loops. A regression test verifies fast-fail behavior.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • NVIDIA/aicr#1252: Modifies in-process Chainsaw executor behavior related to assertion/evaluation execution.
  • NVIDIA/aicr#1245: Related updates to pod waiting-reason JMESPath assertions.
  • NVIDIA/aicr#1243: Prior work touching the Grove health-check YAML referenced in this PR.

Suggested labels

bug, area/validator, area/tests, size/M

Suggested reviewers

  • mchmarny
  • lockwobr
  • njhensley
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix(validator): fail fast on eval errors; nil-safe health checks' directly and accurately summarizes the main changes: fixing evaluation errors to fail fast and making health check expressions nil-safe.
Description check ✅ Passed The description is comprehensive and fully related to the changeset, explaining the three regression fixes, motivation, implementation details, testing, and risk assessment with direct references to the actual changes.
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.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@yuanchen8911
yuanchen8911 requested a review from mchmarny June 9, 2026 20:21
mchmarny
mchmarny previously approved these changes Jun 9, 2026

@mchmarny mchmarny left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Three clean, targeted fixes for the deployment-phase hang regression. The error-code reclassification (ErrCodeInternal → ErrCodeInvalidRequest for checkErr) is semantically correct — eval errors are a malformed-expression problem, not an internal one — and the isTerminalAssertErr placement in both retry loops is right (after nil check, before sleep). The || \[]`` JMESPath coalescing is applied consistently across all 22 files. The dynamo label-match is a solid fix that generalizes correctly to any release-name prefix.

One medium concern: the fast-fail path that prevents the 8-minute hang has no unit test. If someone later changes the error code on checkErr, the hang silently returns. Suggest adding a short retry-loop test before this merges. One nit on comment length. CI fully green including on-cluster Tier 1.

Comment thread validators/chainsaw/inprocess.go Resolved
Comment thread validators/chainsaw/inprocess.go Resolved
@yuanchen8911
yuanchen8911 force-pushed the fix/deployment-health-check-eval-and-nil-safety branch from 9b512cf to 6461d05 Compare June 9, 2026 20:27
@yuanchen8911
yuanchen8911 requested review from a team and njhensley June 9, 2026 20:33
@yuanchen8911
yuanchen8911 force-pushed the fix/deployment-health-check-eval-and-nil-safety branch from 6461d05 to 45c5c1a Compare June 9, 2026 20:36
@yuanchen8911
yuanchen8911 requested a review from mchmarny June 9, 2026 20:37

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@validators/chainsaw/inprocess_test.go`:
- Around line 300-360: The test
TestRunChainsawTestInProcess_TerminalEvalErrorFailsFast only exercises the
named-resource branch via f.addGet; add a second subcase that omits
metadata.name in the YAML produced by makeYAML and instead calls f.addList(...)
with the same healthy resource set so the list-based code path is exercised;
keep the same throwExpr, runChainsawTestInProcess invocation, and the same
assertions about r.Error and elapsed so the list-based (nil-status/List)
terminal-eval behavior is covered alongside the existing named-resource case.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: dec03ec3-0707-4379-bac0-dec9a243e8ab

📥 Commits

Reviewing files that changed from the base of the PR and between 6461d05 and 45c5c1a.

📒 Files selected for processing (24)
  • recipes/checks/agentgateway/health-check.yaml
  • recipes/checks/aws-ebs-csi-driver/health-check.yaml
  • recipes/checks/aws-efa/health-check.yaml
  • recipes/checks/cert-manager/health-check.yaml
  • recipes/checks/dynamo-platform/health-check.yaml
  • recipes/checks/gatekeeper/health-check.yaml
  • recipes/checks/gpu-operator/health-check.yaml
  • recipes/checks/grove/health-check.yaml
  • recipes/checks/k8s-ephemeral-storage-metrics/health-check.yaml
  • recipes/checks/k8s-nim-operator/health-check.yaml
  • recipes/checks/kai-scheduler/health-check.yaml
  • recipes/checks/kube-prometheus-stack/health-check.yaml
  • recipes/checks/kubeflow-trainer/health-check.yaml
  • recipes/checks/kueue/health-check.yaml
  • recipes/checks/network-operator/health-check.yaml
  • recipes/checks/nfd/health-check.yaml
  • recipes/checks/nodewright-operator/health-check.yaml
  • recipes/checks/nvidia-dra-driver-gpu/health-check.yaml
  • recipes/checks/nvsentinel/health-check.yaml
  • recipes/checks/prometheus-adapter/health-check.yaml
  • recipes/checks/slinky-slurm-operator/health-check.yaml
  • recipes/checks/slinky-slurm/health-check.yaml
  • validators/chainsaw/inprocess.go
  • validators/chainsaw/inprocess_test.go

Comment thread validators/chainsaw/inprocess_test.go Resolved
@mchmarny mchmarny removed the bug label Jun 9, 2026
@yuanchen8911
yuanchen8911 force-pushed the fix/deployment-health-check-eval-and-nil-safety branch from 45c5c1a to bd466de Compare June 9, 2026 21:30
@github-actions github-actions Bot added size/L and removed size/M labels Jun 9, 2026
@yuanchen8911
yuanchen8911 force-pushed the fix/deployment-health-check-eval-and-nil-safety branch from bd466de to 090c858 Compare June 9, 2026 21:46
Deployment-phase health-check validation regressed in the recent
in-process executor + deepened-check stack (NVIDIA#1235/NVIDIA#1245/NVIDIA#1252):

1. inprocess.go: runAssertWithRetry/runErrorWithRetry retried ANY
   non-nil error, so a permanent JMESPath evaluation error was retried
   for the entire assert window (6m) instead of failing fast like the
   old chainsaw binary did. Classify assertion-engine errors as
   ErrCodeInvalidRequest (terminal) and short-circuit the retry loops
   on them. Adds a regression test asserting terminal eval errors
   fail fast (< AssertRetryInterval) rather than retrying to deadline.

2. recipes/checks/*: the (init)containerStatuses[?...] | length(@)
   projection throws 'invalid type for: <nil>' on any pod without
   (init) containers (the common case), feeding defect #1. Coalesce to
   an empty array across all 22 affected component health checks.

3. recipes/checks/dynamo-platform: validate-deployment-exists asserted
   a Deployment named 'dynamo-operator', but the chart prefixes it with
   the release name (dynamo-platform-dynamo-operator-controller-manager),
   so the assert never matched and retried to the deadline. Match by the
   stable app.kubernetes.io/name=dynamo-operator label instead.

Verified on an EKS H100 cluster: deployment phase goes from an 8m
timeout (status=other) to PASSED in ~21s; full deployment 4/4 and
conformance 11/11 green.
@yuanchen8911
yuanchen8911 force-pushed the fix/deployment-health-check-eval-and-nil-safety branch from c76ef97 to 598e58e Compare June 9, 2026 22:00
@yuanchen8911
yuanchen8911 merged commit fa14e51 into NVIDIA:main Jun 9, 2026
116 checks passed
@yuanchen8911
yuanchen8911 deleted the fix/deployment-health-check-eval-and-nil-safety branch June 9, 2026 22:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants