Populate Network Path metadata for CNM connections - #52902
Populate Network Path metadata for CNM connections#52902AlexandreYang wants to merge 13 commits into
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7bc40e5460
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| connCount++ | ||
| if !s.shouldScheduleNetworkPathForConn(conn, origin, vpcSubnets) { | ||
| hasTest := s.shouldScheduleNetworkPathForConn(conn, origin, vpcSubnets) | ||
| decisions = append(decisions, npmodel.NetworkPathScheduleDecision{HasTest: hasTest}) |
There was a problem hiding this comment.
Avoid collecting decisions for ignored scheduling calls
When Network Path scheduling runs from the current production call sites I checked (comp/netflow/flowaggregator/aggregator.go:204, pkg/network/sender/sender_linux.go:324, and pkg/process/checks/net.go:185), the returned decisions are discarded. This append still allocates a backing slice for every yielded connection; in the NetFlow path it happens once per flow, so enabling network_path.netflow_monitoring adds an allocation on every flow even though no enrichment is populated yet. Please keep the old no-result scheduling path or make decision collection opt-in until a caller consumes it.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 11ed778918
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| scheduledConns[i].NetworkPath = &model.NetworkPath{ | ||
| HasTest: decision.HasTest, | ||
| } |
There was a problem hiding this comment.
Plumb Network Path decisions through direct sender
Setting NetworkPath here only enriches the process-agent connections check path. In environments with network_config.direct_send: true, ConnectionsCheck.IsEnabled returns false (pkg/process/checks/net.go:143) and the Linux direct sender is the producer; that path still calls ScheduleNetworkPathTests and discards the returned decisions (pkg/network/sender/sender_linux.go:324), while encodeConnection never writes a network-path field. Those direct-send CNM deployments will schedule tests but continue sending connections without network_path.has_test, so please carry the decisions into the direct sender encoder as well.
Useful? React with 👍 / 👎.
|
🎯 Code Coverage (details) 🔗 Commit SHA: 5de868d | Docs | Datadog PR Page | Give us feedback! |
Files inventory check summaryFile checks results against ancestor 1d93f4e9: Results for datadog-agent_7.82.0~devel.git.442.5de868d.pipeline.121530583-1_amd64.deb:No change detected |
Static quality checks✅ Please find below the results from static quality gates Successful checksInfo
11 successful checks with minimal change (< 2 KiB)
|
Regression DetectorRegression Detector ResultsMetrics dashboard Baseline: 1d93f4e ❌ Experiments with retried target crashesThis is a critical error. One or more replicates failed with a non-zero exit code. These replicates may have been retried. See Replicate Execution Details for more information.
Optimization Goals: ✅ Improvement(s) detected
|
| perf | experiment | goal | Δ mean % | Δ mean % CI | trials | links |
|---|---|---|---|---|---|---|
| ➖ | quality_gate_idle_all_features | memory utilization | -2.76 | [-2.79, -2.73] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_idle | memory utilization | -3.13 | [-3.18, -3.08] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_security_mean_fs_load | memory utilization | -3.63 | [-3.66, -3.59] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_security_no_fs_load | memory utilization | -3.69 | [-3.79, -3.60] | 1 | Logs bounds checks dashboard |
| ➖ | quality_gate_security_idle | memory utilization | -3.71 | [-3.77, -3.66] | 1 | Logs bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | memory utilization | -6.71 | [-6.94, -6.48] | 1 | Logs bounds checks dashboard |
| ✅ | quality_gate_logs | % cpu utilization | -47.13 | [-47.95, -46.30] | 1 | Logs bounds checks dashboard |
Bounds Checks: ✅ Passed
| perf | experiment | bounds_check_name | replicates_passed | observed_value | links |
|---|---|---|---|---|---|
| ✅ | quality_gate_idle | intake_connections | 10/10 | 3 ≤ 4 | bounds checks dashboard |
| ✅ | quality_gate_idle | memory_usage | 10/10 | 145.67MiB ≤ 154MiB | bounds checks dashboard |
| ✅ | quality_gate_idle | total_bytes_received | 10/10 | 576.98KiB ≤ 819.20KiB | bounds checks dashboard |
| ✅ | quality_gate_idle_all_features | intake_connections | 10/10 | 3 ≤ 4 | bounds checks dashboard |
| ✅ | quality_gate_idle_all_features | memory_usage | 10/10 | 489.64MiB ≤ 495MiB | bounds checks dashboard |
| ✅ | quality_gate_idle_all_features | total_bytes_received | 10/10 | 0.89MiB ≤ 1.25MiB | bounds checks dashboard |
| ✅ | quality_gate_logs | intake_connections | 10/10 | 4 ≤ 6 | bounds checks dashboard |
| ✅ | quality_gate_logs | memory_usage | 10/10 | 180.93MiB ≤ 195MiB | bounds checks dashboard |
| ✅ | quality_gate_logs | missed_bytes | 10/10 | 0B = 0B | bounds checks dashboard |
| ✅ | quality_gate_logs | total_bytes_received | 10/10 | 264.19MiB ≤ 292MiB | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | cpu_usage | 10/10 | 332.60 ≤ 2000 | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | intake_connections | 10/10 | 3 ≤ 6 | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | memory_usage | 10/10 | 391.67MiB ≤ 430MiB | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | missed_bytes | 10/10 | 0B = 0B | bounds checks dashboard |
| ✅ | quality_gate_metrics_logs | total_bytes_received | 10/10 | 0.86GiB ≤ 1.04GiB | bounds checks dashboard |
| ✅ | quality_gate_security_idle | cpu_usage | 10/10 | 28.38 ≤ 40 | bounds checks dashboard |
| ✅ | quality_gate_security_idle | memory_usage | 10/10 | 293.69MiB ≤ 330MiB | bounds checks dashboard |
| ✅ | quality_gate_security_mean_fs_load | cpu_usage | 10/10 | 60.62 ≤ 80 | bounds checks dashboard |
| ✅ | quality_gate_security_mean_fs_load | memory_usage | 10/10 | 275.47MiB ≤ 310MiB | bounds checks dashboard |
| ✅ | quality_gate_security_no_fs_load | cpu_usage | 10/10 | 23.09 ≤ 40 | bounds checks dashboard |
| ✅ | quality_gate_security_no_fs_load | memory_usage | 10/10 | 283.52MiB ≤ 320MiB | bounds checks dashboard |
Explanation
Confidence level: 90.00%
Effect size tolerance: |Δ mean %| ≥ 5.00%
Performance changes are noted in the perf column of each table:
- ✅ = significantly better comparison variant performance
- ❌ = significantly worse comparison variant performance
- ➖ = no significant change in performance
A regression test is an A/B test of target performance in a repeatable rig, where "performance" is measured as "comparison variant minus baseline variant" for an optimization goal (e.g., ingress throughput). Due to intrinsic variability in measuring that goal, we can only estimate its mean value for each experiment; we report uncertainty in that value as a 90.00% confidence interval denoted "Δ mean % CI".
For each experiment, we decide whether a change in performance is a "regression" -- a change worth investigating further -- if all of the following criteria are true:
-
Its estimated |Δ mean %| ≥ 5.00%, indicating the change is big enough to merit a closer look.
-
Its 90.00% confidence interval "Δ mean % CI" does not contain zero, indicating that if our statistical model is accurate, there is at least a 90.00% chance there is a difference in performance between baseline and comparison variants.
-
Its configuration does not mark it "erratic".
Replicate Execution Details
We run multiple replicates for each experiment/variant. However, we allow replicates to be automatically retried if there are any failures, up to 8 times, at which point the replicate is marked dead and we are unable to run analysis for the entire experiment. We call each of these attempts at running replicates a replicate execution. This section lists all replicate executions that failed due to the target crashing or being oom killed.
Note: In the below tables we bucket failures by experiment, variant, and failure type. For each of these buckets we list out the replicate indexes that failed with an annotation signifying how many times said replicate failed with the given failure mode. In the below example the baseline variant of the experiment named experiment_with_failures had two replicates that failed by oom kills. Replicate 0, which failed 8 executions, and replicate 1 which failed 6 executions, all with the same failure mode.
| Experiment | Variant | Replicates | Failure | Logs | Debug Dashboard |
|---|---|---|---|---|---|
| experiment_with_failures | baseline | 0 (x8) 1 (x6) | Oom killed | Debug Dashboard |
The debug dashboard links will take you to a debugging dashboard specifically designed to investigate replicate execution failures.
❌ Retried Normal Replicate Execution Failures (non-profiling)
| Experiment | Variant | Replicates | Failure | Debug Dashboard |
|---|---|---|---|---|
| quality_gate_idle | baseline | 7 | Oom killed | Debug Dashboard |
❌ Retried Profiling Replicate Execution Failures (ddprof)
Note: Profiling replicas may still be executing. See the debug dashboard for up to date status.
| Experiment | Variant | Replicates | Failure | Debug Dashboard |
|---|---|---|---|---|
| quality_gate_idle | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_idle_all_features | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_idle_all_features | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_logs | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_logs | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_metrics_logs | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_metrics_logs | comparison | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_idle | baseline | 10 | Oom killed | Debug Dashboard |
| quality_gate_security_no_fs_load | comparison | 10 | Oom killed | Debug Dashboard |
CI Pass/Fail Decision
✅ Passed. All Quality Gates passed.
- quality_gate_idle_all_features, bounds check intake_connections: 10/10 replicas passed. Gate passed.
- quality_gate_idle_all_features, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_idle_all_features, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check intake_connections: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
- quality_gate_logs, bounds check missed_bytes: 10/10 replicas passed. Gate passed.
- quality_gate_security_idle, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_idle, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_mean_fs_load, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_mean_fs_load, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_no_fs_load, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_security_no_fs_load, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check cpu_usage: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check missed_bytes: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_metrics_logs, bounds check intake_connections: 10/10 replicas passed. Gate passed.
- quality_gate_idle, bounds check memory_usage: 10/10 replicas passed. Gate passed.
- quality_gate_idle, bounds check intake_connections: 10/10 replicas passed. Gate passed.
- quality_gate_idle, bounds check total_bytes_received: 10/10 replicas passed. Gate passed.
| ScheduleNetflowPathTests(conns iter.Seq[npmodel.NetworkPathConnection]) | ||
| // ScheduleNetworkPathTests schedules dynamic Network Path tests for CNM | ||
| // connections and returns one NetworkPath per yielded connection. | ||
| ScheduleNetworkPathTests(conns iter.Seq[npmodel.NetworkPathConnection]) []npmodel.NetworkPath |
There was a problem hiding this comment.
I do not have all the context so feel free to ignore.
What if instead of returning a slice we return an iterator with the npmodel.NetworkPathConnection like:
ScheduleNetworkPathTests(conns iter.Seq[npmodel.NetworkPathConnection]) iter.Seq2[npmodel.NetworkPathConnection, npmodel.NetworkPath]
That way we can get rid of the two arrays synced together: networkPaths and scheduledConns.
Implementation — yield each pair lazily as connections are processed:
func (s *npCollectorImpl) scheduleNetworkPathTests(...) iter.Seq2[npmodel.NetworkPathConnection, npmodel.NetworkPath] {
return func(yield func(npmodel.NetworkPathConnection, npmodel.NetworkPath) bool) {
// ... getVPCSubnets, startTime setup ...
for conn := range conns {
var path npmodel.NetworkPath
if s.shouldScheduleNetworkPathForConn(conn, origin, vpcSubnets) {
pathtest := s.makePathtest(conn, origin)
path = npmodel.NetworkPath{HasTest: true, TestIdentity: makeTestIdentity(...)}
if err := s.scheduleOne(&pathtest); err != nil {
s.logger.Errorf(...)
}
}
if !yield(conn, path) {
return
}
}
// emit timing/count metrics
}
}Consumer in net.go — drops to one parallel slice instead of two, gets npc directly from the range:
func (c *ConnectionsCheck) scheduleNetworkPath(conns *model.Connections) {
var scheduledModelConns []*model.Connection
connsIter := func(yield func(npmodel.NetworkPathConnection) bool) {
for _, conn := range conns.Conns {
// ... build npc, parse IPs ...
if !yield(npc) { return }
scheduledModelConns = append(scheduledModelConns, conn)
}
}
i := 0
for npc, path := range c.npCollector.ScheduleNetworkPathTests(connsIter) {
if i >= len(scheduledModelConns) { break }
scheduledModelConns[i].NetworkPath = &model.NetworkPath{HasTest: path.HasTest}
if path.HasTest {
scheduledModelConns[i].NetworkPath.TestIdentity = path.TestIdentity
logNetworkPathConnection(npc, path)
}
i++
}
}|
This pull request has been automatically marked as stale because it has not had activity in the past 15 days. It will be closed in 30 days if no further activity occurs. If this pull request is still relevant, adding a comment or pushing new commits will keep it open. Also, you can always reopen the pull request if you missed the window. Thank you for your contributions! |
Summary
npmodel.NetworkPathvalues from NPCollector scheduling pathsConnection.NetworkPath.HasTeston evaluated CNM connections using the collector resultgithub.com/DataDog/agent-payload/v5to the companion payload schema withConnection.NetworkPath.HasTestCompanion PR
Health Platform issue state note
The agent-payload bump also regenerates the Health Platform proto definitions. In that regenerated code,
ISSUE_STATE_NEWandISSUE_STATE_ONGOINGare deprecated;ISSUE_STATE_ACTIVEandISSUE_STATE_RESOLVEDare the canonical values going forward.This PR updates Agent Health Platform code and tests to emit and assert
ISSUE_STATE_ACTIVEfor active issues, while still loading legacy persistednew/ongoingstates as active. This is not part of the CNM Network Path runtime behavior, but it is required so the Agent continues to pass staticcheck after consuming the updated agent-payload module.Tests
git diff --checkGOPROXY=https://proxy.golang.org,direct dda inv go.tidyGOPROXY=https://proxy.golang.org,direct dda inv test --targets=./pkg/process/checks --extra-args='-run TestScheduleNetworkPathSetsConnectionMetadata'GOPROXY=https://proxy.golang.org,direct dda inv test --targets=./comp/networkpath/npcollector/impl --extra-args='-run Test_npCollectorImpl_ScheduleNetworkPathTests'Note: parallel
dda inv testattempts fornpcollectorcan fail before running tests due to a localddatemporaryuv-*cleanup race; the same command passed when rerun by itself.