feat(proxy): shared registry, deterministic ports, and new management commands#261
Conversation
|
Claude finished @stevenolen's task —— View job PR Review: feat(proxy): shared registry, deterministic ports, and new management commands
Overall this is well-structured — the registry file-locking design is sound, the API surface is clean, and tests cover the key paths. A few items to consider: Important1. Truncate-then-write is not crash-safe —
var buf bytes.Buffer
enc := json.NewEncoder(&buf)
enc.SetIndent("", " ")
if err := enc.Encode(m); err != nil {
return fmt.Errorf("encoding registry: %w", err)
}
if err := f.Truncate(0); err != nil { ... }
if _, err := f.Seek(0, io.SeekStart); err != nil { ... }
if _, err := f.Write(buf.Bytes()); err != nil { ... }2. Port collision detection removed from The old 3.
4.
5. Daemon mode silently discards In daemon mode, Suggestions6. Use String concatenation ( func RegistryFilePath() string {
return filepath.Join(DataDir(), "proxies.json")
}7. It calls 8. Deterministic port range — 1000-port range (10000–10999) gives ~40% collision probability at 30 workloads (birthday paradox). This is probably fine for current usage, but if the range can be widened cheaply (e.g., 10000–19999), it'd provide more headroom. At minimum, this ties back to point #2 — collisions should produce a clear error. Looks Good
|
|
@claude re-review |
|
Claude finished @stevenolen's task —— View job Re-review: feat(proxy): shared registry, deterministic ports, and new management commands
Previous review items — status
All 8 items from the first review have been addressed. Current state — looks goodThe implementation is clean. A few minor observations (none blocking):
LGTM — nice work addressing all the feedback. The registry locking, buffer-then-write pattern, collision detection, and test coverage are all solid. |
|
Follow-up: kubeconfig construction is duplicated across several files While fixing the hardcoded port 1080 references, I noticed kubeconfig generation is implemented independently in multiple places:
Each step builds its own kubeconfig inline because they run as isolated Pulumi invocations and each needs cluster access independently. This is why the hardcoded-1080 bug appeared in five places instead of one — every kubeconfig-building site had to be patched separately. Worth consolidating into a single |
|
Heads up: one-time Pulumi state migration on first apply after merge Steps that write for every affected cluster/site resource. This is expected — apply it and the state stabilises permanently. This only matters in the Pulumi execution context (i.e. |
|
@claude review again |
|
Claude finished @stevenolen's task —— View job Re-review: feat(proxy): shared registry, deterministic ports, and new management commands
Previous review items — all 8 addressed ✓All items from reviews #1 and #2 are addressed. The two new commits ( New findings1. Python Pulumi code still has hardcoded The Go side is fully migrated, but three Python files still use the old hardcoded port:
These are used during If these Python files are only called during steps where Worth fixing in this PR or as a tracked follow-up — this is the same class of bug the last two commits addressed on the Go side. 2. Both Looks good
LGTM on the Go side. The Python hardcoded ports (#1 above) are the remaining gap. |
|
@claude review again |
|
Claude finished @stevenolen's task —— View job Re-review: feat(proxy): shared registry, deterministic ports, and new management commands
Previous review items — all addressedAll items from reviews #1–#3 are addressed:
New finding
The // clusters.go:74
envVars["ALL_PROXY"] = fmt.Sprintf("socks5://localhost:%d", proxy.WorkloadPort(s.DstTarget.Name()))But Since Fix: add // helm.go, after line 44
if !s.DstTarget.TailscaleEnabled() {
envVars["ALL_PROXY"] = fmt.Sprintf("socks5://localhost:%d", proxy.WorkloadPort(s.DstTarget.Name()))
}Alternatively, set it in Minor observations (non-blocking)
Everything else looks good
The helm step gap is the only remaining issue. |
not the first time that's been said on this pr 😆 |
…ment commands Replace single proxy.json with a shared proxies.json registry (file-locked via syscall.Flock) so multiple proxies can run concurrently. Assign each workload a deterministic SOCKS5 port derived from FNV-32a (range 10000–10999); ensure, workon, and k9s use this port automatically, while `ptd proxy` defaults to 1080 for interactive use and the deterministic port for --daemon mode. New: ptd proxy --list (with live status), --prune, --stop (no target stops all), and ptd proxy port <target> to print the deterministic port.
- saveRegistryToHandle: encode to buffer before truncating (crash-safe write) - Preflight: detect hash collisions by scanning registry for same-port conflicts - registry.go: add platform comment (syscall.Flock is Linux/macOS only) - --daemon/--stop: demote from PersistentFlags to Flags (don't bleed to subcommands) - daemon branch: comment explaining intentional process orphan - RegistryFilePath: use filepath.Join for consistency - GetRunningProxy: direct map lookup instead of ListRunningProxies + linear scan - WorkloadPort: widen range to 10000–19999 (10000 slots vs 1000)
…vives ptd exit exec.CommandContext kills its child when the context is cancelled. In daemon mode ptd exits after starting the proxy, which cancelled the context and immediately killed the subprocess. Use context.Background() for daemon starts so the proxy process is decoupled from ptd's lifetime.
…ses the correct SOCKS5 port The kubeconfig proxy-url was hardcoded to socks5://localhost:1080. With deterministic per-workload ports, SetupKubeConfig now receives the actual local port and injects it correctly.
ensure steps (clusters, postgres_config, sites, clusters_aws, clusters_azure) were injecting socks5://localhost:1080 into ALL_PROXY env vars and kubeconfig proxy-url fields. These now use the deterministic workload port so they work correctly when multiple proxies are running concurrently.
…ove dead Go fallbacks Python aws_workload, azure_workload, and aws_eks_cluster now read ALL_PROXY from the environment (with 1080 fallback) for kubeconfig proxy-url, matching the port already injected by Go step callers. Dead localPort="1080" fallbacks removed from aws and azure NewProxySession constructors.
PruneRegistry was removing stale entries without calling KillProcess, leaving orphaned processes running for Azure dual-PID sessions where one process had died but the other was still alive.
…ehavior The helm step was not passing ALL_PROXY to the Python subprocess, causing cluster_kubeconfig() to fall through to the socks5://localhost:1080 default while the proxy runs on the deterministic workload port. Also updates PTD_CLI_REFERENCE.md and ensure-flow.md to reflect the new port scheme (interactive → 1080, daemon/ensure/workon → 10000–19999) and the renamed proxies.json registry file.
6f99d41 to
ddbb595
Compare
What
Replaces the single
proxy.jsonwith a sharedproxies.jsonregistry so multiple proxy sessions can run concurrently — unblocking parallelworkon/ensureinvocations and multi-session Claude usage.Changes
Registry (
lib/proxy/registry.go— new)proxies.jsonkeyed by target name, serialised undersyscall.Flock(exclusive write, shared read) to avoid concurrent-write corruptionListRunningProxies,PruneRegistry,StopAllpublic APIRunningProxy.Store()/DeleteFile()updated to upsert/remove from the registry transparently — no changes needed inaws/orazure/proxy codeDeterministic ports (
lib/proxy/proxy.go)WorkloadPort(name string) int— FNV-32a hash of the workload name, range 10000–10999ensure,workon, andk9suseWorkloadPort(t.Name())automaticallyptd proxy <target>defaults to 1080 for interactive/browser use;--daemonuses the deterministic port so it is reused byensure/workonNew CLI surface (
cmd/proxy.go)ptd proxy --list— tabular output with live running/stopped statusptd proxy --prune— remove stale registry entries (dead PIDs)ptd proxy --stop(no target) — stop all running proxiesptd proxy port <target>— print the deterministic port for a workloadTesting
lib/proxy/registry_test.go: store/list round-trip, delete, prune dead PIDs, empty registry, upsert overwritelib/proxy/proxy_test.go:WorkloadPortstability and range,DeleteFileregistry semanticscmd/proxy_test.go: new flags andportsubcommand registration