HealthEvent Data Model Reference

View as Markdown

This document is the authoritative reference for the HealthEvent data model — the fundamental unit of data that flows through NVSentinel. Every fault detected by any health monitor is represented as a HealthEvent, and every downstream module (quarantine, drain, remediation, export) consumes and enriches this structure.

Audience: Developers building custom health monitors, writing CEL quarantine rules, integrating external systems via the event exporter, or debugging the fault-remediation pipeline.

Document type: Reference. Expected lifetime: same as the proto schema it describes. This document must be updated in the same PR that modifies data-models/protobufs/health_event.proto or data-models/protobufs/external_remediation.proto. If you change a field, enum value, or status transition in those files, update the corresponding section here before merging.

Table of Contents


Where the Model Lives

ArtifactPathPurpose
Protobuf definitiondata-models/protobufs/health_event.protoWire format and CRD generation source
Generated Go typesdata-models/pkg/protos/health_event.pb.goImport as github.com/nvidia/nvsentinel/data-models/pkg/protos
Go extensionsdata-models/pkg/model/health_event_extentions.goHelper constants and GetEffectiveActionName()
gRPC servicedata-models/protobufs/health_event.protoPlatformConnector serviceIngestion RPC used by all health monitors
External remediationdata-models/protobufs/external_remediation.protoCRD for handoff to external repair systems

Core Message: HealthEvent

1message HealthEvent \{
2 uint32 version = 1;
3 string agent = 2;
4 string componentClass = 3;
5 string checkName = 4;
6 bool isFatal = 5;
7 bool isHealthy = 6;
8 string message = 7;
9 RecommendedAction recommendedAction = 8;
10 repeated string errorCode = 9;
11 repeated Entity entitiesImpacted = 10;
12 map<string, string> metadata = 11;
13 google.protobuf.Timestamp generatedTimestamp = 12;
14 string nodeName = 13;
15 BehaviourOverrides quarantineOverrides = 14;
16 BehaviourOverrides drainOverrides = 15;
17 ProcessingStrategy processingStrategy = 16;
18 string id = 17;
19 string customRecommendedAction = 18;
20\}

Field Reference

If you are building a custom health monitor, the table below shows what happens when a field is omitted or left at its zero value. See Writing a Health Monitor for the end-to-end walkthrough.

#FieldTypeDescriptionIf omitted / zero value
1versionuint32Protocol version. Currently 1.Ingestion may reject the event. Always set to 1.
2agentstringName of the health monitor that produced the event (e.g. "gpu-health-monitor", "syslog-health-monitor", "csp-health-monitor"). Used in metrics labels, log correlation, and fault-quarantine rule matching for cordon/taint actions. This field should always be set to a stable identifier (e.g., the monitor’s deployment name) so that quarantine rules can reliably match on it.Metrics and logs lose source attribution. Quarantine rules that match on agent will not fire. Event is still accepted.
3componentClassstringCategory of the affected component. Common values: "GPU", "gce_instance", "EC2", "Software", "NIC". Consumed by CEL quarantine rules for filtering.CEL rules that filter on componentClass will not match. Quarantine may not trigger.
4checkNamestringIdentifier of the specific check that fired (e.g. "xid-check", "sxid-check", "CSPMaintenance"). The deduplication transformer uses this as its suppression key.Deduplication cannot suppress repeats. Every poll produces a new actionable event.
5isFatalboolWhether the fault is considered fatal (remediation required; the node/component can no longer process user workloads). Quarantine rules typically require isFatal == true to cordon a node.Defaults to false. Most quarantine rules will not match — the node stays schedulable.
6isHealthyboolfalse for fault events, true for recovery events. A recovery event can un-quarantine a node if all active faults have cleared.Defaults to false (treated as a fault). A recovery monitor must set this to true or it will re-quarantine instead of clearing.
7messagestringHuman-readable description of the fault. Surfaced in Kubernetes node conditions and exported CloudEvents.Node condition shows an empty message. Operators see the fault but not what it is.
8recommendedActionRecommendedActionEnum directing what remediation should occur. See RecommendedAction Enum.Defaults to NONE. Event is stored but no remediation CR is created.
9errorCoderepeated stringMachine-readable error identifiers (e.g. ["XID_48", "XID_79"]). Used in CEL rules and alerting.CEL rules matching on errorCode will not fire. Alerting integrations lose granularity.
10entitiesImpactedrepeated EntitySpecific hardware entities affected. See Entity.GPU Reset cannot target a specific GPU — falls back to node-level action or skips.
11metadatamap<string, string>Arbitrary key-value pairs. Monitors attach diagnostic context (driver version, PCI address, XID details). Propagated to CloudEvents export.No diagnostic context in exported events. Debugging requires correlating with monitor logs.
12generatedTimestampTimestampWhen the monitor detected the fault. Used for deduplication windows and metric duration calculations.Dedup window anchoring and remediation-duration metrics become inaccurate.
13nodeNamestringKubernetes node name where the fault was detected. The primary routing key for all downstream modules.Required. Platform connector rejects events without a node name.
14quarantineOverridesBehaviourOverridesPer-event override for quarantine behavior. See BehaviourOverrides.No override — CEL rules evaluate normally.
15drainOverridesBehaviourOverridesPer-event override for drain behavior. See BehaviourOverrides.No override — per-namespace eviction strategies apply normally.
16processingStrategyProcessingStrategyControls whether downstream modules may modify cluster state. See ProcessingStrategy Enum.UNSPECIFIED is normalized to EXECUTE_REMEDIATION at ingestion. Full remediation pipeline runs.
17idstringUnique event identifier. Assigned by the platform connector on ingestion if not set by the monitor.Platform connector generates a UUID. No action needed from the monitor.
18customRecommendedActionstringFree-form action name when recommendedAction == CUSTOM. Must be non-empty (validated at ingestion). Maps to a Helm-configured remediation action.Rejected at ingestion if recommendedAction == CUSTOM and this field is empty.

RecommendedAction Enum

Directs the fault-remediation module on what repair action to trigger.

ValueNumericMeaningTypical Remediation
NONE0No remediation action recommendedNo repair CR created. Storage and cluster mutations (quarantine, drain) remain governed by processingStrategy.
COMPONENT_RESET2Reset a specific component (GPU, NIC)GPU Reset CRD targeting entitiesImpacted
CONTACT_SUPPORT5Automated remediation not possible; human intervention requiredAlert / ticket creation; human action ranges from pod restart to hardware escalation
RUN_FIELDDIAG6Run field diagnosticsDiagnostic job
RESTART_VM15Restart virtual machineCSP reboot via janitor-provider
RESTART_BM24Reboot bare-metal nodeCSP reboot or generic Job-based reboot
REPLACE_VM25Terminate and replace VMCSP terminate via janitor-provider
RUN_DCGMEUD26Run DCGM End-User DiagnosticsDiagnostic pod
CUSTOM27User-defined actionResolved via customRecommendedAction → Helm maintenance.actions map
UNKNOWN99Unrecognized actionLogged and skipped

Routing logic (in fault-remediation):

1// data-models/pkg/model/health_event_extentions.go
2func GetEffectiveActionName(he *protos.HealthEvent) string \{
3 if he.RecommendedAction == protos.RecommendedAction_CUSTOM \{
4 return he.CustomRecommendedAction
5 \}
6 return he.RecommendedAction.String()
7\}

The effective action name is looked up in the Helm-configured maintenance.actions map to find the CRD template, API group, kind, and completion condition to create.


ProcessingStrategy Enum

Controls whether downstream modules (fault-quarantine, node-drainer, fault-remediation) may modify cluster state in response to this event.

ValueNumericBehavior
UNSPECIFIED0Normalized to EXECUTE_REMEDIATION by the platform connector at ingestion. Custom monitors that omit this field get full remediation.
EXECUTE_REMEDIATION1Normal behavior. All downstream modules process the event and may cordon, drain, and remediate.
STORE_ONLY2Observability only. Event is persisted and exported but no module modifies cluster resources.
STORE_AND_ANALYSE3Event is persisted, exported, and available to the health-events-analyzer, but no direct cluster modifications (no cordon/drain/remediate).

Where strategy is enforced:

  • Platform connector normalizes UNSPECIFIEDEXECUTE_REMEDIATION at ingestion.
  • Deduplication transformer downgrades repeated unhealthy events to STORE_AND_ANALYSE within a suppression window (see ADR-039).
  • Fault-quarantine skips events where processingStrategy != EXECUTE_REMEDIATION.
  • Health-events-analyzer queries for STORE_AND_ANALYSE events specifically.

BehaviourOverrides

1message BehaviourOverrides \{
2 bool force = 1;
3 bool skip = 2;
4\}

Per-event overrides that let a health monitor bypass default pipeline behavior.

quarantineOverrides

FieldEffect
force = trueQuarantine the node regardless of CEL rule evaluation.
skip = trueDo not quarantine even if rules would normally match.

drainOverrides

FieldEffect
force = trueForce immediate eviction for all namespaces, ignoring per-namespace eviction strategies (allow-completion timeouts are bypassed).
skip = trueSkip drain entirely. The event’s UserPodsEvictionStatus is marked AlreadyDrained so fault-remediation proceeds immediately.

Use case: Debug/test events (e.g. fault-injection demos) set drainOverrides.skip = true to exercise the remediation pipeline without waiting for pod eviction.


Entity (Impacted Resources)

1message Entity \{
2 string entityType = 1;
3 string entityValue = 2;
4\}

Identifies specific hardware entities affected by the fault.

entityTypeentityValue exampleUsed by
"GPU""0", "GPU-a1b2c3d4-..."GPU Reset CRD (targets specific GPU UUID)
"PCI""0000:17:00.0"Tracing span attributes, diagnostics
"NIC""mlx5_0"NIC health correlation

The entitiesImpacted array is propagated to:

  • Tracing: each entity becomes a span attribute health_event.entities_impacted.<type>.
  • Event exporter: serialized into the CloudEvents payload.
  • GPU Reset: the janitor uses GPU UUIDs from entities to target the reset CRD.

Storage Wrapper: HealthEventWithStatus

Events are stored in MongoDB (or PostgreSQL) wrapped in a status envelope:

1// data-models/pkg/model/health_event_extentions.go
2type HealthEventWithStatus struct \{
3 CreatedAt time.Time `bson:"createdAt"`
4 HealthEvent *protos.HealthEvent `bson:"healthevent,omitempty"`
5 HealthEventStatus *protos.HealthEventStatus `bson:"healtheventstatus"`
6\}

The HealthEvent portion is immutable after ingestion (except for dedup strategy downgrade). The HealthEventStatus portion is progressively enriched by each downstream module as it processes the event.


HealthEventStatus Lifecycle

1message HealthEventStatus \{
2 string nodeQuarantined = 1;
3 google.protobuf.Timestamp quarantineFinishTimestamp = 2;
4 OperationStatus userPodsEvictionStatus = 3;
5 google.protobuf.Timestamp drainFinishTimestamp = 4;
6 google.protobuf.BoolValue faultRemediated = 5;
7 google.protobuf.Timestamp lastRemediationTimestamp = 6;
8 map<string, string> spanIds = 7;
9\}

Each field is written by a specific module at a specific pipeline stage:

FieldWritten byValues / Meaning
nodeQuarantinedfault-quarantine"Quarantined", "UnQuarantined", "AlreadyQuarantined", "Cancelled"
quarantineFinishTimestampfault-quarantineWhen quarantine processing completed
userPodsEvictionStatusnode-drainerOperationStatus\{status, message\} — see below
drainFinishTimestampnode-drainerWhen drain processing completed
faultRemediatedfault-remediationBoolValuenil (absent) = not yet processed; true = repair CR created and confirmed; false = repair failed or skipped
lastRemediationTimestampfault-remediationWhen the remediation CR was last created
spanIdsall modulesDistributed tracing span IDs per service (e.g. \{"platform-connector": "abc123", "fault-quarantine": "def456"\})

OperationStatus values (userPodsEvictionStatus.status)

StatusMeaning
NotStartedDrain has not begun
InProgressPods are being evicted
SucceededAll user pods evicted successfully
FailedEviction encountered an error
AlreadyDrainedDrain was skipped (via drainOverrides.skip or prior completion)

Status progression diagram


CRD Projection: HealthEventResource

For Kubernetes-native storage (experimental), the HealthEvent maps to a CRD:

1message HealthEventResource \{
2 option (protoc_gen_crd.k8s_crd) = \{
3 api_group: "healthevents.dgxc.nvidia.com",
4 kind: "HealthEventResource",
5 plural: "healtheventresources",
6 singular: "healtheventresource",
7 categories: ["nvidia", "gpu"]
8 \};
9 HealthEvent spec = 1;
10 HealthEventStatus status = 2;
11\}

The spec field holds the immutable HealthEvent; the status field holds the progressively-enriched HealthEventStatus. This mirrors the standard Kubernetes spec/status convention.


External Remediation Request

When the configured remediation action produces an ExternalRemediationRequest (ExtRR) — for any recommendedAction, not only CUSTOM — the full HealthEvent is embedded in the CRD spec:

1message ExternalRemediationRequestSpec \{
2 HealthEvent healthEvent = 1;
3\}

The ExtRR is cluster-scoped (like RebootNode, TerminateNode, GPUReset CRDs) and carries status conditions for coordination with external repair systems:

Condition TypeSet byMeaning
NVSentinelOwnershipReleasedExtRR reconcilerNVSentinel has released the node (taint applied, ready for external work)
ExternalRemediationCompleteExternal systemExternal repair is done; NVSentinel can re-admit the node

See ADR-040 for the full design.


Tracing Correlation

Each module that processes an event writes its span ID into HealthEventStatus.spanIds[serviceName]. This enables end-to-end trace correlation:

platform-connector → fault-quarantine → node-drainer → fault-remediation

The span ID written to the datastore becomes the parent span for the next module’s processing, creating a causal chain across independent services that communicate only through MongoDB change streams.

See Distributed Tracing for setup and querying.


Examples

GPU XID fault (fatal, triggers reboot)

1\{
2 "version": 1,
3 "agent": "syslog-health-monitor",
4 "componentClass": "GPU",
5 "checkName": "xid-check",
6 "isFatal": true,
7 "isHealthy": false,
8 "message": "XID 79: GPU has fallen off the bus",
9 "recommendedAction": "RESTART_BM",
10 "errorCode": ["XID_79"],
11 "entitiesImpacted": [
12 \{"entityType": "GPU", "entityValue": "GPU-a1b2c3d4-e5f6-a7b8-c9d0-e1f2a3b4c5d6"\},
13 \{"entityType": "PCI", "entityValue": "0000:17:00.0"\}
14 ],
15 "metadata": \{"driverVersion": "570.86.15"\},
16 "nodeName": "gpu-node-42",
17 "processingStrategy": "EXECUTE_REMEDIATION"
18\}

Recovery event (un-quarantine)

1\{
2 "version": 1,
3 "agent": "gpu-health-monitor",
4 "componentClass": "GPU",
5 "checkName": "dcgm-health-check",
6 "isFatal": false,
7 "isHealthy": true,
8 "message": "All GPU health checks passing",
9 "recommendedAction": "NONE",
10 "nodeName": "gpu-node-42",
11 "processingStrategy": "EXECUTE_REMEDIATION"
12\}

Custom remediation with drain skip

1\{
2 "version": 1,
3 "agent": "custom-monitor",
4 "componentClass": "Software",
5 "checkName": "memory-pressure",
6 "isFatal": true,
7 "isHealthy": false,
8 "message": "Uncorrectable memory pressure detected",
9 "recommendedAction": "CUSTOM",
10 "customRecommendedAction": "slack-notify-ops",
11 "drainOverrides": \{"skip": true\},
12 "nodeName": "worker-7",
13 "processingStrategy": "EXECUTE_REMEDIATION"
14\}