Skip to content

feat: test-connectivity refactor with matrix - #1761

Merged
Frostman merged 3 commits into
masterfrom
ema/test-connectivity
Jul 30, 2026
Merged

feat: test-connectivity refactor with matrix#1761
Frostman merged 3 commits into
masterfrom
ema/test-connectivity

Conversation

@edipascale

@edipascale edipascale commented May 21, 2026

Copy link
Copy Markdown
Contributor

replace a number of ad-hoc testing function with a declarative, matrix-based test. Reachability checks that are currently supported by Fabric are preserved as is; additional checks are manually overlayed on the matrix, e.g. for NAT tests.

Copilot AI 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.

Pull request overview

This PR refactors hhfab connectivity testing from a set of ad-hoc, imperative checks into a declarative, matrix-based model that can be repopulated from live peering state and then overlaid with additional expectations (notably for NAT and port-forward scenarios).

Changes:

  • Introduces a new ConnectivityMatrix model and a matrix-driven connectivity runner (TestConnectivityWithMatrix / DoVLABTestConnectivityWithMatrix).
  • Updates VPC setup to return discovered per-server endpoints (with IP/HostBGP metadata) to seed the matrix.
  • Refactors multiple runtime test suites (VPC peerings, NAT, externals, failover helpers) to accept an optional matrix and use matrix-based connectivity where appropriate.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
pkg/hhfab/vlabrunner.go Updates SetupVPCs callsites to ignore the new returned endpoints.
pkg/hhfab/testing.go Adds server IP discovery helper; changes SetupVPCs to return endpoints; refactors connectivity prelude and ping/iperf pair execution.
pkg/hhfab/rt_utils.go Routes failover connectivity checks through matrix-based runner when a matrix is provided.
pkg/hhfab/rt_static_external.go Updates test function signature to accept an optional matrix parameter.
pkg/hhfab/rt_single_vpc_suite.go Updates suite test signatures and forwards matrix into connectivity checks where supported.
pkg/hhfab/rt_no_vpc_suite.go Updates suite test signatures (matrix parameter unused for these cases).
pkg/hhfab/rt_nat_tests.go Refactors NAT tests to a spec+overlay pattern that annotates the connectivity matrix with NAT expectations.
pkg/hhfab/rt_nat_external_tests.go Moves NAT external validation to matrix overlays plus a retained stability ping helper.
pkg/hhfab/rt_multi_vpc_single_subnet_suite.go Converts multiple peering scenarios to run via the matrix-based connectivity runner.
pkg/hhfab/rt_multi_vpc_multi_subnet_suite.go Uses matrix-based connectivity for subnet filtering test; updates signatures elsewhere.
pkg/hhfab/rt_base.go Extends TestFunc signature to accept a matrix and builds an initial matrix during suite setup.
pkg/hhfab/matrix.go Adds the matrix data model, repopulation logic, NAT overlay helpers, and the matrix-driven connectivity runner.
pkg/hhfab/cmdvlab.go Changes DoVLABSetupVPCs to return endpoints from SetupVPCs.
cmd/hhfab/main.go Updates CLI setup-vpcs path to ignore returned endpoints.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pkg/hhfab/testing.go
Comment thread pkg/hhfab/matrix.go
@edipascale edipascale added ci:+release Enable VLAB release tests ci:+hlab Enable hybrid VLAB tests labels May 21, 2026
@github-actions

github-actions Bot commented May 22, 2026

Copy link
Copy Markdown

Release Tests

 12 files   48 suites   3h 59m 18s ⏱️
 45 tests  43 ✅   2 💤 0 ❌
540 runs  215 ✅ 325 💤 0 ❌

Results for commit 709bff4.

♻️ This comment has been updated with latest results.

@edipascale
edipascale force-pushed the ema/test-connectivity branch 4 times, most recently from 9add36d to 45674d6 Compare May 22, 2026 13:25
@edipascale

Copy link
Copy Markdown
Contributor Author

@pau-hedgehog I plan on doing another pass to remove some of the verbose comments and simplify the code in a few places, but this should be ready to be reviewed, at least in terms of the approach used

@edipascale
edipascale marked this pull request as ready for review May 22, 2026 15:35
@edipascale
edipascale requested review from a team as code owners May 22, 2026 15:35
@edipascale
edipascale force-pushed the ema/test-connectivity branch 3 times, most recently from 39fff37 to 32b0ed1 Compare May 26, 2026 16:49
@edipascale
edipascale requested a review from Copilot May 27, 2026 07:30

Copilot AI 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.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated no new comments.

@Frostman
Frostman requested a review from pau-hedgehog June 2, 2026 15:48
@edipascale
edipascale force-pushed the ema/test-connectivity branch 2 times, most recently from f88e533 to c44067e Compare June 8, 2026 15:17
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

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

Adds ConnectivityMatrix domain and probe phases, implements SSH-based server endpoint discovery over VPC attachments and concurrent IP matching, changes SetupVPCs to return collected endpoints, introduces connectivity test helpers (reachCheckUnsupported sentinel, prepareConnectivityTest, populateConnectivityMatrix), and wires a shared ConnectivityMatrix through VLAB test harness and all test suites (including NAT test conversion) to execute matrix-driven connectivity checks instead of legacy queries.

Changes

Connectivity Matrix–Driven Testing

Layer / File(s) Summary
Connectivity matrix types and probe execution
pkg/hhfab/matrix.go
Defines domain model (Endpoint, ServerEndpoint, ExternalEndpoint, ConnectivityExpectation, ProtoPort, TranslatedAddress, ConnectivityVerdict) and matrix construction/lifecycle APIs (NewConnectivityMatrix, BuildConnectivityMatrix, BuildConnectivityMatrixFromCluster, Add, Lookup, Repopulate, IsSameEndpointNode, OverlayMatrixNAT). Implements TestConnectivityWithMatrix orchestration with server↔server ping/iperf3, server→external curl, and port-forward iperf3 phases; DNAT destination-IP selection; bidirectional iperf3 eligibility gating; and TCP reachability polling for port-forward execution. Includes DoVLABTestConnectivityWithMatrix wrapper entrypoint.
SSH endpoint discovery and reconciliation
pkg/hhfab/endpoints.go, pkg/hhfab/endpoints_test.go
Introduces SSHResolver type and SSHResolverFromMap adapter. Implements discoverServerIPs to SSH-run ip address show, parse interface/CIDR pairs, filter loopback/docker0/enp2s0. Adds CollectServerEndpoints to list VPC attachments, resolve connections uniquely to server endpoint names, match discovered IPs to narrowest-prefix-containing attachments, and emit Endpoint objects. Implements ReplaceServerEndpoints reconciliation logic to update matching endpoints in-place (preserving pointer identity), append new, drop stales, and prune stale connectivity entries. Nine unit tests validate in-place updates, VPC moves, multi-attachment handling, nil receiver safety, and HostBGP preservation.
SetupVPCs returns discovered endpoints
pkg/hhfab/testing.go
Changes SetupVPCs return signature from error to ([]*Endpoint, error), adds/strengthens option validation, manages P2P mode enforcement from switch profiles, improves error wrapping throughout resource management (kube client, switch listing, SSH config, VLAN/subnet iterators, netconf construction, VPC/attachment cleanup/creation), and calls CollectServerEndpoints after server configuration to return discovered endpoints.
Connectivity test preparation and reachability helpers
pkg/hhfab/testing.go
Introduces reachCheckUnsupported sentinel for unsupported Expose.As/Not cases; adds prepareConnectivityTest helper to centralize SSH config/kube client/switch prelude and cache management; implements populateConnectivityMatrix to reset and repopulate matrix expectations by iterating endpoint pairs and applying reachability helpers (skipping unsupported via errors.Is); updates gateway reachability paths to return/propagate reachCheckUnsupported sentinel; refactors TestConnectivity to use helpers with discoverServerIPs requiring exactly one eligible IP per server.
SetupVPCs callers and signature propagation
cmd/hhfab/main.go, pkg/hhfab/cmdvlab.go, pkg/hhfab/vlabrunner.go
Updates DoVLABSetupVPCs to return ([]*Endpoint, error) and adjusts error path on loadVLABForHelpers failure; updates CLI command handler and on-ready step to destructure endpoints (discarding where unused) while preserving error handling through shutdown-and-pause paths.
Test harness matrix threading and lifecycle
pkg/hhfab/rt_base.go
Updates TestFunc contract to accept *ConnectivityMatrix alongside context and testCtx; changes setupTest to return (*ConnectivityMatrix, error) by building initial matrix from collected endpoints after VPC setup and L3 stabilization delay (or empty matrix in noSetup mode); updates doRunSuite to capture matrix during initial and between-test re-setup; threads matrix into each test.F call.
Test utilities conditional matrix execution
pkg/hhfab/rt_utils.go
Updates shutDownLinkAndTest to accept optional matrix parameter and conditionally run DoVLABTestConnectivityWithMatrix when non-nil, otherwise run DoVLABTestConnectivity. Updates auxiliary suite test signatures (no-vpc, on-ready, static-external, eslag-fallback) to accept matrix parameter (unused in function body).
NAT matrix overlays and shared harness
pkg/hhfab/rt_nat_external_tests.go, pkg/hhfab/rt_nat_tests.go
Implements overlayExternalSNAT to parse NAT pool CIDR and set SourcePool, overlayExternalPortForward to validate and set DNAT destination IP/port, pingExternalStability to probe external BGP neighbor IP. Adds natTestSpec and runNATTest shared harness that lists/sorts VPCs, builds peering specs, sets up peerings, waits for readiness, repopulates matrix, applies optional overlay, and runs TestConnectivityWithMatrix. Includes DNAT offset computation, directional verdict overrides, endpoint rebinding, and vpcFirstSubnetCIDR helper enforcing single-subnet VPCs.
Multi-VPC suite matrix adoption
pkg/hhfab/rt_multi_vpc_multi_subnet_suite.go, pkg/hhfab/rt_multi_vpc_single_subnet_suite.go
Propagates matrix parameter across multi-VPC test entrypoints; each test repopulates matrix after peering setup and runs DoVLABTestConnectivityWithMatrix instead of non-matrix connectivity checks, covering VPC starter, full-mesh, only-externals, full-loop, Sergei special, gateway peering, gateway peering loop, and mixed gateway/fabric external scenarios.
Single-VPC suite matrix adoption and endpoint rebinding
pkg/hhfab/rt_single_vpc_suite.go
Adds matrix parameter to test signatures (MCLAG, ESLAG, Bundled, spine, gateway, mesh, no-restrictions, with-restrictions, DNS/NTP/MTU, DHCP renewal, ROCE); passes matrix into shutDownLinkAndTest calls. Enhances dhcpStaticLeaseTest revert flow to SSH and run networkctl reconfigure on saved interface, sleep, then call rebindMatrixServerEndpoint to refresh endpoint state after DHCP restoration.
External NAT scenarios converted to matrix flow
pkg/hhfab/rt_nat_external_tests.go
Refactors all BGP and static-external NAT tests (no-NAT, static-NAT, masquerade, port-forward, masquerade+port-forward variants) to accept matrix, repopulate matrix after peerings, wait for NAT pool route propagation, apply SNAT/DNAT overlays, run DoVLABTestConnectivityWithMatrix, and invoke pingExternalStability for non-port-forward-only cases.
Gateway NAT scenarios converted to shared harness
pkg/hhfab/rt_nat_tests.go
Converts NAT gateway peering tests to runNATTest wrappers with per-case BuildSpec and overlay functions for masquerade, static DNAT, bidirectional static DNAT, port-forward, and masquerade+port-forward NAT. Updates overlap NAT test to matrix-driven flow: repopulate matrix after peerings, rebind moved server endpoint into overlap VPC, apply static DNAT overlays in both directions, and run TestConnectivityWithMatrix; updates revert closure to rebind endpoint after restoration.

Possibly related PRs

  • githedgehog/fabricator#1290: Related changes to test-suite runner wiring and TestFunc/doRunSuite signatures when introducing matrix threading through on-ready and release test flow.

Suggested reviewers

  • Frostman
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 79.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: test-connectivity refactor with matrix' accurately captures the main change: refactoring test-connectivity functionality using a matrix-based approach.
Description check ✅ Passed The description 'replace a number of ad-hoc testing function with a declarative, matrix-based test' is directly related to the changeset, explaining the core refactoring objective and the matrix-based testing approach.
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.


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

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/hhfab/rt_nat_external_tests.go (1)

362-374: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Guard As4() against non-IPv4 NAT pools.

Both inverted port-forward paths call prefix.Masked().Addr().As4() after checking only the prefix length. If the annotation is malformed or IPv6, this panics the runner instead of returning a normal test error.

Suggested fix
 prefix, err := netip.ParsePrefix(bgpNATCIDR)
 if err != nil {
 	return false, nil, fmt.Errorf("parsing BGP NAT CIDR %s: %w", bgpNATCIDR, err)
 }
+if !prefix.Addr().Is4() {
+	return false, nil, fmt.Errorf("BGP NAT CIDR %s must be IPv4", bgpNATCIDR) //nolint:goerr113
+}
 if prefix.Bits() != 24 {
 	return false, nil, fmt.Errorf("BGP NAT CIDR %s must be a /24 for the .200 inverted NAT address to be valid", bgpNATCIDR) //nolint:goerr113
 }

Apply the same guard in staticExternalPortForwardNATGatewayTest.

Also applies to: 797-809

🤖 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 `@pkg/hhfab/rt_nat_external_tests.go` around lines 362 - 374, The code calls
prefix.Masked().Addr().As4() without verifying the address is IPv4, which panics
for malformed or IPv6 NAT pools; update the parsing in the function containing
the shown snippet and likewise in staticExternalPortForwardNATGatewayTest to
check prefix.Addr().Is4() (or inspect the Addr returned by
prefix.Masked().Addr()) before calling As4(), and return a formatted error
(instead of panicking) when the address is not IPv4 so the test runner reports a
normal error; ensure you replace direct As4() usage around the
prefix.Masked().Addr().As4() calls with this guarded check and error path.
🤖 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 `@pkg/hhfab/endpoints.go`:
- Around line 241-260: The loop can append multiple Endpoints for the same
attachment because it doesn't skip attachments already claimed in the used
slice; modify the block that picks att := atts[bestIdx] to first check if
used[bestIdx] is true and continue if so, then mark used[bestIdx] = true and
only then append the new Endpoint (affecting the loop over p.ips, the used
slice, and the creation of Endpoint for serverName/vpc/subnet); this ensures
each attachment index produces at most one Endpoint and preserves
ReplaceServerEndpoints' (vpc, subnet) reconciliation contract.

In `@pkg/hhfab/matrix.go`:
- Around line 543-576: The deduplication map extTargets currently keys only on
pfTargetKey{ip,port} which collapses multiple distinct (src,dst) probes; update
the key to include the source (e.g., add a source identifier like
src.Server.Name or src endpoint id) so uniqueness is per (src,ip,port).
Concretely, extend pfTargetKey to include a source field, update where keys are
constructed (the place using pfTargetKey{ip: e.NAT.DestinationIP, port:
e.NAT.DestinationPort}) and any lookups/insertions into extTargets, and keep
using reachabilityFromExpectation(matrix.Lookup(...)) and pfTargetVal as before;
this preserves per-source probe tracking and avoids skipping other sources to
the same external target.

In `@pkg/hhfab/rt_nat_tests.go`:
- Around line 617-629: Do not restore the cached origEndpoints snapshot on
revert; instead re-discover the moved server's current endpoints from
matrix.AllEndpoints at revert time to avoid re-installing stale IPs. Replace
usage of the origEndpoints slice (and any re-install logic that uses those
*Endpoint pointers after ReplaceServerEndpoints) with a fresh lookup that
filters matrix.AllEndpoints for ep.Server != nil && ep.Server.Name ==
targetServer (or call a dedicated helper like FindEndpointsForServer if present)
and use that fresh set when reattaching the server so DHCP-changed leases are
respected.

In `@pkg/hhfab/testing.go`:
- Around line 1888-1940: populateConnectivityMatrix is calling IsServerReachable
and IsExternalSubnetReachable with only server names, which ORs across all
attachments and incorrectly marks every (server, vpc, subnet) EndpointPair as
allowed; update the population to perform attachment-scoped reachability checks:
add/introduce a new reachability API (or overload) that accepts both endpoint
attachment identities (server, vpc, subnet) for source and destination, then
replace calls to IsServerReachable and IsExternalSubnetReachable inside
populateConnectivityMatrix so that for each src and dst Endpoint (from
m.AllEndpoints) you pass the specific attachment info and use that
attachment-scoped response to set ConnectivityExpectation on the corresponding
EndpointPair; ensure you preserve the same error handling (including
reachCheckUnsupported) and set Reason/Peering from the new result.

---

Outside diff comments:
In `@pkg/hhfab/rt_nat_external_tests.go`:
- Around line 362-374: The code calls prefix.Masked().Addr().As4() without
verifying the address is IPv4, which panics for malformed or IPv6 NAT pools;
update the parsing in the function containing the shown snippet and likewise in
staticExternalPortForwardNATGatewayTest to check prefix.Addr().Is4() (or inspect
the Addr returned by prefix.Masked().Addr()) before calling As4(), and return a
formatted error (instead of panicking) when the address is not IPv4 so the test
runner reports a normal error; ensure you replace direct As4() usage around the
prefix.Masked().Addr().As4() calls with this guarded check and error path.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2ca5fe06-03ef-4c89-bff8-d64305ff05b2

📥 Commits

Reviewing files that changed from the base of the PR and between cbdfbc7 and c44067e.

📒 Files selected for processing (16)
  • cmd/hhfab/main.go
  • pkg/hhfab/cmdvlab.go
  • pkg/hhfab/endpoints.go
  • pkg/hhfab/endpoints_test.go
  • pkg/hhfab/matrix.go
  • pkg/hhfab/rt_base.go
  • pkg/hhfab/rt_multi_vpc_multi_subnet_suite.go
  • pkg/hhfab/rt_multi_vpc_single_subnet_suite.go
  • pkg/hhfab/rt_nat_external_tests.go
  • pkg/hhfab/rt_nat_tests.go
  • pkg/hhfab/rt_no_vpc_suite.go
  • pkg/hhfab/rt_single_vpc_suite.go
  • pkg/hhfab/rt_static_external.go
  • pkg/hhfab/rt_utils.go
  • pkg/hhfab/testing.go
  • pkg/hhfab/vlabrunner.go

Comment thread pkg/hhfab/endpoints.go
Comment thread pkg/hhfab/matrix.go Outdated
Comment thread pkg/hhfab/rt_nat_tests.go Outdated
Comment thread pkg/hhfab/testing.go
@edipascale
edipascale force-pushed the ema/test-connectivity branch from c44067e to 4ee922e Compare June 9, 2026 10:49

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/hhfab/rt_nat_tests.go (1)

538-589: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Pick an unused valid VLAN instead of originalVLAN + 100.

Line 538 assumes originalVLAN + 100 is always safe, but this test runs against whatever VLANs the suite already has. If that VLAN is already allocated, or originalVLAN is near the top of the valid range, the overlap VPC create/readiness path will fail for reasons unrelated to NAT. Choose a free VLAN from the current VPC inventory and validate it before building overlapVPC.

🤖 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 `@pkg/hhfab/rt_nat_tests.go` around lines 538 - 589, The test currently sets
newVLAN := originalVLAN + 100 which can collide or exceed valid VLAN range;
instead, before creating overlapNS/overlapVPC, scan existing VPCs (via
testCtx.kube.List or the inventory used in these tests) to build a set of used
VLANs, pick the first unused VLAN within the valid range (e.g., 1–4094) and
validate it, then assign that value to newVLAN; use that newVLAN when
constructing overlapVPC (referenced by overlapVPC, overlapNS, originalVLAN) and
fail the test early with a clear error if no free VLAN is found.
🧹 Nitpick comments (1)
pkg/hhfab/rt_on_ready_suite.go (1)

170-170: 💤 Low value

Remove the commented variable declaration.

The commented variable staticExtProxyName is never used. If this is intended for future NAT testing (as suggested by the TODO on line 675), consider either removing it entirely or adding an explanatory TODO comment.

🧹 Proposed cleanup
 	var bgpExtName, staticExtNonProxyName string
-	// var staticExtProxyName string
 	for _, ext := range extList.Items {

Alternatively, if this is planned for future use:

-	// var staticExtProxyName string
+	// TODO: var staticExtProxyName string - will be used for NAT proxy peering tests
🤖 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 `@pkg/hhfab/rt_on_ready_suite.go` at line 170, Remove the unused commented
variable declaration "// var staticExtProxyRemoteIP string" from the file
(pkg/hhfab/rt_on_ready_suite.go) or, if you intend to use it for future NAT
testing, replace the commented declaration with a clear TODO comment that
explains its planned purpose (referencing staticExtProxyRemoteIP) so the intent
is explicit.
🤖 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 `@pkg/hhfab/rt_nat_tests.go`:
- Around line 60-62: The skip-path in runNATTest currently returns an error when
vpcs.Items < 2; change it to mark the case as skipped without an error by
returning skip=true and nil for both result and error (i.e., return true, nil,
nil) so it matches gatewayPeeringOverlapNATTest and lets callers treat it as a
skip rather than a failure; update the return at the vpcs.Items length check
inside runNATTest accordingly.

---

Outside diff comments:
In `@pkg/hhfab/rt_nat_tests.go`:
- Around line 538-589: The test currently sets newVLAN := originalVLAN + 100
which can collide or exceed valid VLAN range; instead, before creating
overlapNS/overlapVPC, scan existing VPCs (via testCtx.kube.List or the inventory
used in these tests) to build a set of used VLANs, pick the first unused VLAN
within the valid range (e.g., 1–4094) and validate it, then assign that value to
newVLAN; use that newVLAN when constructing overlapVPC (referenced by
overlapVPC, overlapNS, originalVLAN) and fail the test early with a clear error
if no free VLAN is found.

---

Nitpick comments:
In `@pkg/hhfab/rt_on_ready_suite.go`:
- Line 170: Remove the unused commented variable declaration "// var
staticExtProxyRemoteIP string" from the file (pkg/hhfab/rt_on_ready_suite.go)
or, if you intend to use it for future NAT testing, replace the commented
declaration with a clear TODO comment that explains its planned purpose
(referencing staticExtProxyRemoteIP) so the intent is explicit.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b04026b9-4dbd-4b10-811d-448c45e2b9c7

📥 Commits

Reviewing files that changed from the base of the PR and between c44067e and 4ee922e.

📒 Files selected for processing (17)
  • cmd/hhfab/main.go
  • pkg/hhfab/cmdvlab.go
  • pkg/hhfab/endpoints.go
  • pkg/hhfab/endpoints_test.go
  • pkg/hhfab/matrix.go
  • pkg/hhfab/rt_base.go
  • pkg/hhfab/rt_multi_vpc_multi_subnet_suite.go
  • pkg/hhfab/rt_multi_vpc_single_subnet_suite.go
  • pkg/hhfab/rt_nat_external_tests.go
  • pkg/hhfab/rt_nat_tests.go
  • pkg/hhfab/rt_no_vpc_suite.go
  • pkg/hhfab/rt_on_ready_suite.go
  • pkg/hhfab/rt_single_vpc_suite.go
  • pkg/hhfab/rt_static_external.go
  • pkg/hhfab/rt_utils.go
  • pkg/hhfab/testing.go
  • pkg/hhfab/vlabrunner.go
🚧 Files skipped from review as they are similar to previous changes (15)
  • pkg/hhfab/rt_static_external.go
  • pkg/hhfab/cmdvlab.go
  • pkg/hhfab/vlabrunner.go
  • pkg/hhfab/rt_utils.go
  • pkg/hhfab/rt_no_vpc_suite.go
  • cmd/hhfab/main.go
  • pkg/hhfab/rt_single_vpc_suite.go
  • pkg/hhfab/rt_multi_vpc_multi_subnet_suite.go
  • pkg/hhfab/rt_base.go
  • pkg/hhfab/endpoints.go
  • pkg/hhfab/rt_multi_vpc_single_subnet_suite.go
  • pkg/hhfab/endpoints_test.go
  • pkg/hhfab/rt_nat_external_tests.go
  • pkg/hhfab/matrix.go
  • pkg/hhfab/testing.go

Comment thread pkg/hhfab/rt_nat_tests.go
@edipascale
edipascale force-pushed the ema/test-connectivity branch 2 times, most recently from fb7fe92 to 479c1b1 Compare June 16, 2026 06:26
@edipascale
edipascale force-pushed the ema/test-connectivity branch from 479c1b1 to 3d9ba10 Compare June 23, 2026 08:18
@pau-hedgehog

Copy link
Copy Markdown
Contributor

Filed the DHCP static lease / stale connectivity matrix issue we found while triaging this branch's failures separately: #1876

@edipascale
edipascale force-pushed the ema/test-connectivity branch from cd3dc5b to e47a567 Compare July 15, 2026 09:58
Copilot AI review requested due to automatic review settings July 22, 2026 06:46
@edipascale
edipascale force-pushed the ema/test-connectivity branch from e47a567 to ce28f3b Compare July 22, 2026 06:46

Copilot AI 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.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated 7 comments.

Comment thread pkg/hhfab/testing.go
Comment thread pkg/hhfab/matrix.go
Comment thread pkg/hhfab/matrix.go
Comment thread pkg/hhfab/matrix.go
Comment thread pkg/hhfab/endpoints.go
Comment thread pkg/hhfab/matrix.go
Comment thread pkg/hhfab/testing.go
Copilot AI review requested due to automatic review settings July 28, 2026 14:42
@edipascale
edipascale force-pushed the ema/test-connectivity branch from ce28f3b to acb7a48 Compare July 28, 2026 14:42

Copilot AI 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.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (5)

pkg/hhfab/matrix.go:467

  • deps.wg is a *sync.WaitGroup, which does not have a Go method. This won’t compile; use Add/Done with a plain goroutine (and keep Wait() as-is).
			deps.wg.Go(func() {
				for _, e := range runPingIperfPair(ctx, opts, args) {
					deps.errChan <- e
				}
			})

pkg/hhfab/matrix.go:522

  • deps.wg is a *sync.WaitGroup, so calling deps.wg.Go(...) won’t compile. Replace this with Add(1) + go func(){ defer Done(); ... }().
		deps.wg.Go(func() {
			logArgs := []any{"from", name, "expected", expected.Reachable}
			if expected.Reachable {
				logArgs = append(logArgs, "reason", expected.Reason)
				if expected.Peering != "" {

pkg/hhfab/matrix.go:587

  • deps.wg is a *sync.WaitGroup (no Go method), so this won’t compile. Use Add/Done and a goroutine.
				deps.wg.Go(func() {
					if ie := runMatrixIperfPortForward(ctx, opts, deps.iperfs, fromName, deps.sshByServer[fromName], target, port, expected); ie != nil {
						deps.errChan <- ie
					}
				})

pkg/hhfab/matrix.go:596

  • deps.wg is a *sync.WaitGroup, which doesn’t have Go. This currently won’t compile; use Add/Done with a goroutine.
		deps.wg.Go(func() {
			if ie := runMatrixIperfPortForward(ctx, opts, deps.iperfs, key.from, deps.sshByServer[key.from], key.ip, key.port, val); ie != nil {
				deps.errChan <- ie
			}
		})

pkg/hhfab/matrix.go:758

  • This port-forward iperf3 path runs via toolbox ... iperf3, but the normal iperf3 checks run inside the always-on iperf3 container (sudo docker exec iperf3 ...). Using toolbox here can reintroduce the memory/ENOMEM behavior the container approach avoids, and it bypasses the existing iperf parsing/min-speed logic. Consider switching to sudo docker exec iperf3 ... -p <port> and (ideally) reusing the same result parsing/min-speed enforcement as checkIPerf/runIPerf3Test.
	secs := opts.IPerfsSeconds
	cmd := fmt.Sprintf("toolbox -E LD_PRELOAD=/lib/x86_64-linux-gnu/libgcc_s.so.1 -q timeout %d iperf3 -J -c %s -p %d -t %d",
		secs+25, toIP.String(), toPort, secs)
	if _, _, iperfErr := retrySSHCmd(ctx, ssh, cmd, from); iperfErr != nil {
		return &IperfError{Source: from, Destination: target, ClientMsg: iperfErr.Error()}

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

Sorry it took me to long. Working through the rest of my review

Comment thread pkg/hhfab/testing.go
}
r, err := IsServerReachable(ctx, kube, src.Server.Name, dst.Server.Name, gatewayEnabled)
if err != nil {
if errors.Is(err, reachCheckUnsupported) {

@pau-hedgehog pau-hedgehog Jul 29, 2026

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.

This skip writes no entry, and Lookup treats missing pairs as Deny, so a pair populate can't evaluate silently becomes "expected unreachable".

On master the same condition fails the run loudly. Same pattern: discovery drops endpoints on
warning, and noSetup returns an empty non-nil matrix (rt_base.go:425). All of these pass green while testing nothing.

Can we check the matrix after populate/overlay before leaning on Deny verdicts?

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.

A golden-file test pinning populate's output for a fixed topology could catch most of this class too

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've attempted to address most of these comments, with this being the most prominent one, in #1910
Specifically for this, the idea is to have a list of "dropped endpoints" which have IPs that do not match any subnet or attachments with no matching IPs. These are part of the matrix and will fail a validate call that runs as the first step of the test connectivity. Nodes with no IPs are still silently glossed over to be compatible with the eslag l3vni issue/workaround

Comment thread pkg/hhfab/matrix.go
if e.Verdict != VerdictAllow {
continue
}
if e.NAT != nil && !e.NAT.SourcePool.IsValid() {

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.

SourcePool decides whether to curl, but the observed source address is never asserted. Same on master, so not blocking, just for follow-up

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

agreed to leave it for a follow-up

Comment thread pkg/hhfab/matrix.go
continue
}
e := matrix.Lookup(src, dst, ProtoPort{})
if e.Verdict != VerdictAllow || e.NAT == nil {

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.

Deny port-forward entries are never probed, so negative coverage doesn't reach port-forwards yet. The Deny entries already keep their NAT details, so the data is there when the runner is ready. Worth a follow-up

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

There should now be infra to handle this, although I did not extend the existing tests to make use of it yet

Comment thread pkg/hhfab/rt_utils.go
if matrix == nil {
connCheckErr = DoVLABTestConnectivity(ctx, testCtx.vlabCfg.WorkDir, testCtx.vlabCfg.CacheDir, testCtx.tcOpts)
} else {
connCheckErr = DoVLABTestConnectivityWithMatrix(ctx, testCtx.vlabCfg.WorkDir, testCtx.vlabCfg.CacheDir, testCtx.tcOpts, matrix)

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.

Spine, gateway and mesh failover receive the matrix but still call the legacy path, while link failover already uses it here. Do you plan to migrate them later?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

migrated in the branch mentioned above

pau-hedgehog
pau-hedgehog previously approved these changes Jul 29, 2026

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

This was huge. It improves our coverage significantly, especially the NAT tests.
There are some suggested follow-ups in the comments, the matrix guard being the main one.
Next thing would be figuring out migration next steps.

Comment thread pkg/hhfab/matrix.go
return fmt.Errorf("matrix entry %s→%s (vpc %s/%s) has no valid target IP", src.Server.Name, dst.Server.Name, dst.Server.VPC, dst.Server.Subnet) //nolint:goerr113
}

expected := reachabilityFromExpectation(entry)

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.

When a probe fails, the error says what was expected but not why the matrix expected it. The entry knows (Reason, Peering) but that's dropped here and only shows at debug level. Including it in the failure message would make errors easier to debug

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

a "why" including reason and peering (or whichever of the two are available if we only have one) has been added

Comment thread pkg/hhfab/matrix.go
// Resolve the SSH config and a toolbox mutex for every unique server
// name referenced by the matrix.
sshByServer := map[string]*sshutil.Config{}
toolboxMutexes := map[string]*sync.Mutex{}

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.

nit: looks unused?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

removed

Comment thread pkg/hhfab/matrix.go
matrix.Add(ConnectivityExpectation{
Pair: EndpointPair{Source: src, Destination: dst},
Verdict: VerdictAllow,
Reason: ReachabilityReasonGatewayPeering,

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.

nit: hardcoding reason to GatewayPeering

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

an existing reason is now preserved; otherwise we use gateway peering as default, which is the one thing we use it for currently e.g. in NAT tests

edipascale and others added 3 commits July 29, 2026 18:03
replace a number of ad-hoc testing function with a declarative,
matrix-based test. Reachability checks that are currently supported
by Fabric are preserved as is; additional checks are manually
overlayed on the matrix, e.g. for NAT tests.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Emanuele Di Pascale <emanuele@githedgehog.com>
Move endpoint collection out of SetupVPCs into a standalone, inspection-
based helper (CollectServerEndpoints in pkg/hhfab/endpoints.go) so the
matrix can model servers with multiple (vpc, subnet) attachments, be
built against pre-existing topologies, and be refreshed per-server after
a runtime config change.

SetupVPCs now delegates to the collector after configuring servers and
keeps its ([]*Endpoint, error) signature. BuildConnectivityMatrixFromCluster
covers the build-from-scratch case. ReplaceServerEndpoints on the matrix
swaps endpoint pointers and wipes stale entries; rebindMatrixServerEndpoint
in the overlap-NAT test now reads (vpc, subnet) from the cluster instead
of being told. The single-IP discoverServerIP is replaced by
discoverServerIPs; the legacy non-matrix TestConnectivity asserts len==1
itself.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Emanuele Di Pascale <emanuele@githedgehog.com>
ensure that followup failover test have up-to-date information

Signed-off-by: Emanuele Di Pascale <emanuele@githedgehog.com>
Copilot AI review requested due to automatic review settings July 29, 2026 16:03
@edipascale
edipascale force-pushed the ema/test-connectivity branch from acb7a48 to 709bff4 Compare July 29, 2026 16:03

Copilot AI 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.

Pull request overview

Copilot reviewed 18 out of 18 changed files in this pull request and generated no new comments.

Comments suppressed due to low confidence (2)

pkg/hhfab/testing.go:2904

  • expose.As is a slice, but the error uses %s, which will format as %!s(...) at runtime. Use %v (or %q if you stringify) so the message is readable while still wrapping reachCheckUnsupported for errors.Is checks.
		if len(expose.As) > 0 {
			return false, fmt.Errorf("%w: gw peering with non-empty expose 'As' %s", reachCheckUnsupported, expose.As)
		}

pkg/hhfab/matrix.go:645

  • toolboxMutexes is populated but never used (it only serves as a dedupe set). This adds confusing dead code; you can dedupe using sshByServer directly and drop the mutex map entirely.
	sshByServer := map[string]*sshutil.Config{}
	toolboxMutexes := map[string]*sync.Mutex{}
	for _, ep := range matrix.AllEndpoints {

@Frostman
Frostman merged commit 3e67dac into master Jul 30, 2026
34 checks passed
@Frostman
Frostman deleted the ema/test-connectivity branch July 30, 2026 07:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:+hlab Enable hybrid VLAB tests ci:+release Enable VLAB release tests

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants