Skip to content

fix(agent): detect single-OOM pods and add node/pod condition matchers - #500

Merged
blue4209211 merged 3 commits into
mainfrom
fix/oom-state-terminated-and-node-matchers
Jun 27, 2026
Merged

fix(agent): detect single-OOM pods and add node/pod condition matchers#500
blue4209211 merged 3 commits into
mainfrom
fix/oom-state-terminated-and-node-matchers

Conversation

@mayankpande88

@mayankpande88 mayankpande88 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Two detection gaps in the agent.

OOM on restartPolicy:Never / Jobs. The pod_oom_killed predicate only checked lastState.terminated, which a container populates after a restart. A pod that OOMs once and never restarts records the kill in state.terminated with an empty lastState, so it was never detected. The predicate now fires off state or lastState via mostRecentOOMKilledContainerStatus (already used by the enricher); the dead lastState-only helper is removed.

Three new Node/Pod matchers that read the watched object directly (independent of Prometheus rule evaluation):

  • node_unschedulable — a node cordoned (spec.unschedulable) for >15m. No Prometheus equivalent.
  • node_pressure — Disk/Memory/PID pressure on a node.
  • pod_unschedulablePodScheduled=False (no node fits) sustained >10m. Slow-start pods (PodScheduled=True) are excluded.

Discovery: convertNode now sends spec.unschedulable so cordon state is available downstream.

extra-scrape-config.yaml: drops the additionalPrometheusRulesMap block, which fully duplicated the agent chart's prometheus-alert-rule.yaml (the chart versions use better ratio/baseline expressions); KubeHpaMaxedOut was being defined twice.

Tests

  • predicates_test.go: OOM state.terminated regression + 10 tests for the new matchers
  • converters_test.go: unschedulable assertion
  • go test ./pkg/triggers/ ./pkg/discovery/ green; fmt/vet clean

Note for reviewers

node_pressure overlaps the upstream KubeNodePressure rule and pod_unschedulable partially overlaps KubePodNotReady. Until those upstream rules are disabled they will double-fire; that retirement is left as a follow-up decision.

OOM detection only fired on lastState.terminated, which a container
populates after a restart. A restartPolicy:Never pod or a Job that OOMs
once records the kill in state.terminated with an empty lastState, so it
was never detected. The pod_oom_killed predicate now fires off either
state or lastState (via mostRecentOOMKilledContainerStatus, already used
by the enricher); the dead lastState-only helper is removed.

Adds three Node/Pod matchers that read the watched object directly, so
they survive a degraded Prometheus rule engine:
- node_unschedulable: a node cordoned for >15m (no Prometheus equivalent)
- node_pressure: Disk/Memory/PID pressure on a node
- pod_unschedulable: PodScheduled=False (no node fits) for >10m

convertNode now sends spec.unschedulable so the cordon state is available
downstream. extra-scrape-config.yaml drops the additionalPrometheusRulesMap
block, which fully duplicated the agent chart's prometheus-alert-rule.yaml.
@mayankpande88
mayankpande88 requested a review from a team as a code owner June 27, 2026 08:26

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Code Review

This pull request removes several Prometheus rules from the scrape configuration and replaces them with built-in agent matchers for unschedulable nodes, node pressure, and unschedulable pods. It also refactors the OOMKilled matcher to support pods with a 'Never' restart policy. The review feedback identifies a critical issue in the node unschedulable matcher where a missing or unparseable taint timestamp causes immediate alerts, bypassing the intended 15-minute grace period. A code suggestion is provided to return false in these scenarios, and the corresponding test should be updated.

Comment thread runner/pkg/triggers/predicates.go
Comment thread runner/pkg/triggers/predicates_test.go Outdated
@github-actions

Copy link
Copy Markdown
Contributor

📦 Image Tags Updated

I've automatically updated the image tags in `charts/nudgebee-agent/values.yaml` to the latest versions from GHCR for the `main` branch.

The image tags are now synchronized with the latest builds and ready for release.

…estamp is present

The node.kubernetes.io/unschedulable taint is added asynchronously after
spec.unschedulable flips, so it's absent on the first cordon update.
Treating a missing timeAdded as sustained fired the matcher immediately,
bypassing the 15m grace and alerting on routine drains/upgrades. Return
false until the taint timestamp can confirm the cordon outlasted the
window.
@github-actions

Copy link
Copy Markdown
Contributor

📦 Image Tags Updated

I've automatically updated the image tags in `charts/nudgebee-agent/values.yaml` to the latest versions from GHCR for the `main` branch.

The image tags are now synchronized with the latest builds and ready for release.

@blue4209211
blue4209211 merged commit 2072de9 into main Jun 27, 2026
8 checks passed
@blue4209211
blue4209211 deleted the fix/oom-state-terminated-and-node-matchers branch June 27, 2026 09:27
blue4209211 pushed a commit that referenced this pull request Jun 29, 2026
* chore(chart): bump nudgebee-agent chart version to 0.1.5

nudgebee-agent-0.1.4 is already released/tagged (2026-06-25, before the
node/pod matcher work landed), so the full-release chart-releaser run
422'd on the existing tag. Bump the chart version so the release cuts a
fresh nudgebee-agent-0.1.5 carrying #500 (matchers) + #501 (alert subject
resolution). appVersion left as-is (decoupled; release pins runner image
by GHCR tag, not appVersion).

* chore: update image tags for main release

---------

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
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.

2 participants