Skip to content

feat(health): add endpoint TCP reachability telemetry - #4696

Open
jayzhudev wants to merge 1 commit into
NVIDIA:mainfrom
jayzhudev:health/connectivity-probing
Open

feat(health): add endpoint TCP reachability telemetry#4696
jayzhudev wants to merge 1 commit into
NVIDIA:mainfrom
jayzhudev:health/connectivity-probing

Conversation

@jayzhudev

Copy link
Copy Markdown
Contributor

Add opt-in TCP reachability observations to carbide-health. This allows metrics and logs consumers to distinguish transport failures from TLS, authentication, and protocol failures.

The collector derives targets and ports from the existing eligibility rules and configuration for Redfish, NVUE REST, gNMI, NMX-T, and NMX-C. BMC probes connect directly to the discovered endpoint, even when a BMC proxy is configured.

Each completed probe emits an endpoint-correlated tcp_port_reachable_state gauge. Structured logging is stateless: unreachable logs every failed probe, while all logs every completed probe. Reachability observations bypass health processors and do not create health reports or persisted alerts.

This feature is disabled by default. To enable, here's an example configuration:

[collectors.reachability]
enabled = true
interval = "30s"
timeout = "3s"
log_mode = "unreachable"

Related issues

Resolves #4658

Type of Change

  • Add - New feature or capability
  • Change - Changes in existing functionality
  • Fix - Bug fixes
  • Remove - Removed features or deprecated functionality
  • Internal - Internal changes (refactoring, tests, docs, etc.)

Breaking Changes

  • This PR contains breaking changes

Testing

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed
  • No testing required (docs, internal refactor, etc.)

Manual Testing

Method:

  • Established an independent TCP baseline with socket connection attempts.
  • Ran health collection against real NVOS switch host endpoints.
  • Inspected Prometheus telemetry, structured JSONL logs, and discovery logs.

Coverage:

  • Seven switch host endpoints.
  • Reachable NVUE REST port 443.
  • Unreachable NMX-T port 9352 and NMX-C port 9370.
  • all and unreachable log modes.

Steps:

  1. Probed each service port independently.

    Observed results:

    nvue_rest_reachable=7
    nmxt_unreachable=7
    nmxc_unreachable=7
    
  2. Enabled log_mode = "all" and inspected /telemetry and JSONL output.

    Selected redacted metric:

    carbide_hardware_health_tcp_port_reachable_state{endpoint_key="<endpoint-key>",endpoint_mac="<endpoint-mac>",endpoint_ip="<endpoint-ip>",collector_type="reachability",serial_number="<switch-serial>",rack_id="<rack-id>",service="nmxt",port="9352",environment="lab",inventory="<inventory>"} 0
    

    Selected redacted log:

    {"endpoint":"<endpoint-key>","collector":"reachability","component_type":"nvlink_switch","severity":"WARN","body":"TCP port is unreachable","attributes":[["message_id","CarbideHealth.1.0.TcpPortUnreachable"],["message_args","[\"nmxt@<endpoint-ip>:9352\"]"],["reachability.service","nmxt"],["reachability.address","<endpoint-ip>"],["reachability.port","9352"],["reachability.state","unreachable"],["reachability.error","Connection refused (os error 61)"]]}
  3. Repeated the fleet run with log_mode = "unreachable".

    Observed results:

    metric_series=21
    reachable_logs=0
    unreachable_logs=84
    

    All 21 metric series remained available. The 84 records represent 14 failed targets across six cycles.

  4. Configured two discovered endpoints with the same test key. The first enabled NVUE REST, while the later duplicate also enabled NMX-T.

    Observed results:

    duplicate_warnings=1
    discovered_endpoint_count_one=1
    first_source_series=1
    later_source_or_nmxt_series=0
    nmxt_collector_started=0
    

Results:

  • Emitted gauges matched the independent TCP baseline.
  • All 21 series included endpoint identity and configured correlation metadata.
  • The isolated JSONL run contained only reachability records and no health or alert records.
  • Duplicate endpoint selection remained consistent between ordinary and reachability collectors.

Additional Notes

A successful probe means only that the TCP handshake completed. It does not validate TLS, authentication, HTTP, gRPC, gNMI, NMX-C subscription, or collector readiness.

@jayzhudev jayzhudev self-assigned this Aug 7, 2026
@jayzhudev
jayzhudev requested a review from a team as a code owner August 7, 2026 06:10
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: b094e789-bf99-4507-92af-ef3941cbea30

📥 Commits

Reviewing files that changed from the base of the PR and between 9d296f6 and 1ae8c68.

📒 Files selected for processing (13)
  • crates/health/example/config.example.toml
  • crates/health/src/collectors/mod.rs
  • crates/health/src/collectors/nmxt.rs
  • crates/health/src/collectors/reachability.rs
  • crates/health/src/config.rs
  • crates/health/src/discovery/context.rs
  • crates/health/src/discovery/iteration.rs
  • crates/health/src/discovery/mod.rs
  • crates/health/src/discovery/reachability.rs
  • crates/health/src/discovery/spawn.rs
  • crates/health/src/endpoint/model.rs
  • crates/health/src/lib.rs
  • crates/health/src/sink/events.rs
🚧 Files skipped from review as they are similar to previous changes (13)
  • crates/health/src/collectors/nmxt.rs
  • crates/health/src/discovery/mod.rs
  • crates/health/src/collectors/mod.rs
  • crates/health/example/config.example.toml
  • crates/health/src/lib.rs
  • crates/health/src/sink/events.rs
  • crates/health/src/discovery/iteration.rs
  • crates/health/src/endpoint/model.rs
  • crates/health/src/discovery/spawn.rs
  • crates/health/src/discovery/context.rs
  • crates/health/src/discovery/reachability.rs
  • crates/health/src/collectors/reachability.rs
  • crates/health/src/config.rs

Summary by CodeRabbit

  • New Features

    • Added optional TCP reachability monitoring for discovered infrastructure endpoints.
    • Configurable probe intervals, timeouts, and logging behavior, including unreachable-only logging.
    • Reachability metrics and lifecycle events are available through direct monitoring sinks.
  • Bug Fixes

    • Improved endpoint deduplication and collector reconciliation when endpoints change or disappear.
    • Prevented reachability events from generating inappropriate health reports.
    • Improved collector startup eligibility and retry behavior.

Walkthrough

This change adds configurable TCP reachability telemetry. Discovery resolves eligible endpoint targets and reconciles periodic collectors. The collector emits metrics and optional logs. Reachability events bypass health-report processing.

Changes

TCP reachability telemetry

Layer / File(s) Summary
Reachability configuration and collector
crates/health/src/config.rs, crates/health/example/config.example.toml, crates/health/src/collectors/*
Defines reachability settings, TCP targets, bounded probes, metrics, structured logs, lifecycle cleanup, and collector exports.
Reachability sink routing
crates/health/src/lib.rs, crates/health/src/sink/events.rs
Filters reachability tracing events and bypasses health-report processors while preserving direct sink delivery.
Shared collector eligibility
crates/health/src/discovery/spawn.rs
Centralizes eligibility checks for Redfish, NVUE REST, gNMI, NMX-T, and NMX-C collectors.
Discovery and collector reconciliation
crates/health/src/discovery/context.rs, crates/health/src/discovery/iteration.rs, crates/health/src/discovery/reachability.rs, crates/health/src/discovery/mod.rs, crates/health/src/endpoint/model.rs
Stores reachability state, deduplicates endpoints, resolves targets and ports, reconciles collector lifecycles, and compares endpoint data for updates.

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

Sequence Diagram(s)

sequenceDiagram
  participant Discovery
  participant Eligibility
  participant ReachabilityCollector
  participant Endpoint
  participant Sink
  Discovery->>Eligibility: evaluate endpoint and collector configuration
  Discovery->>ReachabilityCollector: reconcile targets
  ReachabilityCollector->>Endpoint: open TCP connection with timeout
  Endpoint-->>ReachabilityCollector: success or failure
  ReachabilityCollector->>Sink: emit metric and optional structured log
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely summarizes the addition of endpoint TCP reachability telemetry.
Description check ✅ Passed The description explains the reachability feature, configuration, behavior, testing, and scope covered by the changes.
Linked Issues check ✅ Passed The implementation satisfies issue #4658 by adding configurable TCP probes, endpoint metrics, filtered logs, direct BMC probing, and health-report isolation.
Out of Scope Changes check ✅ Passed The supporting discovery, eligibility, equality, and sink changes directly enable the reachability feature and remain within the linked issue scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

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

🧹 Nitpick comments (2)
crates/health/src/lib.rs (1)

192-216: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add tests for ReachabilityTracingFilter.

The current test only covers ReachabilityProcessorBypass. Add coverage that forwards reachability CollectorEvent::Log events and suppresses reachability metric and lifecycle events. Also verify that non-reachability events still reach the wrapped sink. This protects the log_mode contract independently of processor routing.

As per path instructions, “Prefer findings about behavior, concurrency, resource lifetimes, and missing tests over style-only comments.”

🤖 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 `@crates/health/src/lib.rs` around lines 192 - 216, Add focused tests for
ReachabilityTracingFilter covering three cases: forward reachability
CollectorEvent::Log events, suppress reachability metric and lifecycle events,
and forward non-reachability events regardless of kind. Use a recording or mock
DataSink to assert which events reach the wrapped sink, keeping coverage
independent of ReachabilityProcessorBypass routing.

Source: Path instructions

crates/health/src/config.rs (1)

4554-4573: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Convert the validation test to the scenarios! table.

This test invokes validate() twice with different inputs. The neighbouring validation tests in this file (nmxc_collector_validation, logs_collector_validation, sse_log_config_validation) already express that shape with scenarios! and Outcome. Aligning keeps the failure output uniform and makes new cases cheap to add.

♻️ Proposed table-driven form
     #[test]
-    fn reachability_validation_rejects_non_positive_runtime_values() {
-        let mut config = ReachabilityCollectorConfig {
-            interval: Duration::ZERO,
-            ..ReachabilityCollectorConfig::default()
-        };
-
-        assert_eq!(
-            config.validate().expect_err("zero interval must fail"),
-            "[collectors.reachability].interval must be greater than 0"
-        );
-
-        config.interval = Duration::from_secs(1);
-        config.timeout = Duration::ZERO;
-
-        assert_eq!(
-            config.validate().expect_err("zero timeout must fail"),
-            "[collectors.reachability].timeout must be greater than 0"
-        );
-    }
+    fn reachability_collector_validation() {
+        scenarios!(run = |config: ReachabilityCollectorConfig| config.validate();
+            "valid configuration" {
+                ReachabilityCollectorConfig::default() => Yields(()),
+            }
+
+            "probe cadence" {
+                ReachabilityCollectorConfig {
+                    interval: Duration::ZERO,
+                    ..ReachabilityCollectorConfig::default()
+                } => FailsWith(
+                    "[collectors.reachability].interval must be greater than 0".to_string()
+                ),
+
+                ReachabilityCollectorConfig {
+                    timeout: Duration::ZERO,
+                    ..ReachabilityCollectorConfig::default()
+                } => FailsWith(
+                    "[collectors.reachability].timeout must be greater than 0".to_string()
+                ),
+            }
+        );
+    }
🤖 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 `@crates/health/src/config.rs` around lines 4554 - 4573, Convert
reachability_validation_rejects_non_positive_runtime_values into the scenarios!
table-driven form, using the existing Outcome pattern from neighboring tests
such as nmxc_collector_validation, logs_collector_validation, and
sse_log_config_validation. Represent both zero-interval and zero-timeout
configurations as scenarios with their expected validation errors, while
preserving the current assertions and test coverage.

Source: Coding guidelines

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

Nitpick comments:
In `@crates/health/src/config.rs`:
- Around line 4554-4573: Convert
reachability_validation_rejects_non_positive_runtime_values into the scenarios!
table-driven form, using the existing Outcome pattern from neighboring tests
such as nmxc_collector_validation, logs_collector_validation, and
sse_log_config_validation. Represent both zero-interval and zero-timeout
configurations as scenarios with their expected validation errors, while
preserving the current assertions and test coverage.

In `@crates/health/src/lib.rs`:
- Around line 192-216: Add focused tests for ReachabilityTracingFilter covering
three cases: forward reachability CollectorEvent::Log events, suppress
reachability metric and lifecycle events, and forward non-reachability events
regardless of kind. Use a recording or mock DataSink to assert which events
reach the wrapped sink, keeping coverage independent of
ReachabilityProcessorBypass routing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 6f411b5e-ff23-4df7-8581-b265e4038801

📥 Commits

Reviewing files that changed from the base of the PR and between 9d296f6 and dabefa0.

📒 Files selected for processing (13)
  • crates/health/example/config.example.toml
  • crates/health/src/collectors/mod.rs
  • crates/health/src/collectors/nmxt.rs
  • crates/health/src/collectors/reachability.rs
  • crates/health/src/config.rs
  • crates/health/src/discovery/context.rs
  • crates/health/src/discovery/iteration.rs
  • crates/health/src/discovery/mod.rs
  • crates/health/src/discovery/reachability.rs
  • crates/health/src/discovery/spawn.rs
  • crates/health/src/endpoint/model.rs
  • crates/health/src/lib.rs
  • crates/health/src/sink/events.rs

Signed-off-by: Jay Zhu <jayzhu@nvidia.com>
@jayzhudev
jayzhudev force-pushed the health/connectivity-probing branch from dabefa0 to 1ae8c68 Compare August 7, 2026 06:23
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

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.

feat: expose endpoint TCP reachability through health telemetry

1 participant