Series C — -scan-resolvers subcommand#2
Open
Isusami wants to merge 3 commits into
Open
Conversation
Splits the inline probe path inside RunInitialMTUTests into a single-resolver primitive ProbeResolverMTU(ctx, conn, opts) Result and a multi-resolver helper ScanOnce(ctx, opts) []Result that iterates over candidate resolvers. RunInitialMTUTests now drives ProbeResolverMTU through its existing worker pool (via runConnectionMTUTest) so per-completion logging and counter ordering are unchanged. ScanOnce is the side-effect-free multi-resolver entry point that the upcoming -scan-resolvers subcommand and any future re-discovery trigger will call. The single-resolver primitive is decoupled from *Client through a ProbeResolverMTUOptions struct that carries only what it needs: the per-domain max upload payload, the upload/download probe callables, and an optional transport-opener seam. This narrow seam lets the future -doctor per-resolver tunnel-readiness probe (D3) swap in fixed-MTU upload/download variants without dragging the whole client lifecycle along. The pre-existing per-result side effects (balancer mutation, success log line, accept/reject counter and log) stay inside runConnectionMTUTest; the optimizeMTUResolvers post-processing stays inside RunInitialMTUTests. ScanOnce intentionally does not touch any of them so it can be reused outside the normal client startup path. The refactor lands slightly above the 150 LOC estimate because preserving the partial-measurement semantics on rejection and keeping the worker-pool ordering inside RunInitialMTUTests required collapsing mtuConnectionProbeResult into ProbeResolverMTUResult and adding a Client.buildMTUProbeOptions helper plus a Client.buildScanOnceOptions helper for the upcoming subcommand caller. No behavior change. Tests assert ProbeResolverMTU produces the expected per-connection result for accepted, upload-rejected, download-rejected and transport-failure cases, and that ScanOnce matches an inline ProbeResolverMTU loop on a shared fixture across several worker counts.
Introduces a new -scan-resolvers flag in cmd/client/main.go that
loads the configured resolver list via the existing Bootstrap path,
calls ScanOnce (added in C1), and writes the surviving resolvers
to stdout, one IP per line.
Useful for sanity-checking a resolver list outside the normal client
startup path. The dispatch fires after Bootstrap (so the resolver
catalog is fully loaded into the balancer) but before PrintBanner
and the runtime loop, so no tunnel traffic, ping manager, or async
runtime ever starts in scan mode.
Output format and exit codes are intentionally minimal here: every
accepted result writes "{IP}" to stdout and the command exits 0
on success or 1 if the client cannot be initialized. Wiring of
MTU_SERVERS_FILE_FORMAT and the empty-result / I/O-failure exit
codes lands in the follow-up C3 commit.
The renderer is split into ScanResolvers (high-level entry that
takes a *Client) and an inner scanResolvers (takes pre-built
ScanOnceOptions) so tests can drive the output path with stub
upload/download probes without touching the network or building a
fully-bootstrapped client.
Wires MTUServersFileFormat (TOML key MTU_SERVERS_FILE_FORMAT) into
the -scan-resolvers output renderer; defaults to {IP} (the raw
resolver IP) when unset or trimmed to empty. The renderer reuses
formatMTULogLine so operators get the same placeholder vocabulary
they already use for the MTU success log file ({IP}, {DOMAIN},
{UP_MTU}, {DOWN_MTU}, etc.). Per-result MTU measurements are
spliced onto the Connection copy passed to the formatter so
{UP_MTU} / {DOWN_MTU} resolve to the values just measured by
ProbeResolverMTU rather than stale catalog defaults.
Exit codes (now part of the public contract for scripting):
0 = wrote at least one surviving resolver
1 = setup / config-load / I/O failure (warning on stderr)
2 = empty result, i.e. no resolver survived the scan (warning
on stderr)
Lets operators script around the scan command and reuse the same
resolver-file format they already use elsewhere.
Tests cover: format roundtrip with a custom MTU_SERVERS_FILE_FORMAT
template; blank-format fallback to {IP}; empty result and
all-rejected paths returning exit code 2 with the warning on
stderr; write-failure path returning exit code 1 with the
underlying error surfaced on stderr; nil-client guard on
ScanResolvers returning exit code 1.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a
-scan-resolverssubcommand that probes the configured resolver list outside the normal client startup path and writes surviving resolvers to stdout. Useful for sanity-checking resolvers, scripting, and as a foundation for future-doctor/ re-discovery flows.What changed
ProbeResolverMTU+ScanOnce(refactor) — splits the inline probe path insideRunInitialMTUTestsinto a single-resolver primitive (ProbeResolverMTU, decoupled from*Clientvia an options struct) and a multi-resolver helper (ScanOnce).RunInitialMTUTestsnow drivesProbeResolverMTUthrough its existing worker pool so per-completion logging and counter ordering are unchanged.-scan-resolversflag + caller — new-scan-resolversflag incmd/client/main.godispatches (after Bootstrap, before banner / runtime loop) tointernal/client/scancmd.go, which loads the resolver list, callsScanOnce, and writes results to stdout.MTU_SERVERS_FILE_FORMATif set (default{IP}), reusing the existingformatMTULogLineplaceholder vocabulary so{IP},{DOMAIN},{UP_MTU},{DOWN_MTU}, etc. all work. Exit codes:0= wrote at least one resolver,2= empty result (warn on stderr),1= setup / I/O failure.How it works
ProbeResolverMTU(ctx, conn, opts) Resultis the unit of work — one resolver, one probe outcome. It takes aProbeResolverMTUOptionsstruct (rather than*Client) so it can be reused outside the normal client lifecycle. The seam is intentionally narrow: just the per-domain max upload payload, the upload/download probe callables, and an optional transport-opener for tests.ScanOnce(ctx, opts) []Resultiterates the candidate resolvers and aggregates per-resolver results in input order, with worker-pool fan-out clamped to[1, len(connections)].ScanOnceis intentionally side-effect free — no balancer mutation, no logging, no rendering — so callers layer their own post-processing on top.-scan-resolverssubcommand short-circuits before the normal client startup: it loads config + connections via the existingBootstrappath, builds the scan options viaClient.buildScanOnceOptions, callsScanOnce, renders the surviving resolvers usingMTU_SERVERS_FILE_FORMAT(default{IP}), prints them to stdout, and exits with the documented code.RunInitialMTUTestspath now callsProbeResolverMTUindirectly throughrunConnectionMTUTest— no observable behavior change for normal client startup.API layering
ProbeResolverMTU(single-resolver primitive) is the one a future-doctorflow (D3) is expected to reuse — each resolver probed once atMIN_UPLOAD_MTUvia a fixed-MTUUploadProbe/DownloadProbeinstead of the binary-search variants used today.ScanOnce(multi-resolver helper) is what-scan-resolvers(this PR) and any future re-discovery trigger call.Example usage
Test plan
go vet ./...go build ./...go test ./...ScanOncematches an inlineProbeResolverMTUloop on a shared fixture across several worker counts.ProbeResolverMTUproduces the expected per-connection result for accepted, upload-rejected, download-rejected, and transport-failure cases.-scan-resolverswrites the expected resolver lines to stdout with the default{IP}format.MTU_SERVERS_FILE_FORMATroundtrips through the output renderer (placeholders include the per-result{UP_MTU}/{DOWN_MTU}measurements).MTU_SERVERS_FILE_FORMATfalls back to the raw resolver IP.ScanOnceresult and all-rejected paths return exit code2with a warning on stderr.1with the underlying error surfaced on stderr.ScanResolversreturns exit code1.