Phase 8e: cluster-ping migrates to connect_lan_first
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 12s

Same shape as Phase 8c did for cluster-peer-status + cluster-repair.
New flags: --tailscale-addr (optional) + --lan-probe-ms (default 200).
Route (LAN vs tailnet) printed on the output. Zero flag = identical
to pre-8 single-addr behavior.

Fourth of four operator-facing CLIs now routing-aware
(cluster-peer-status, cluster-repair, cluster-ping done; cluster-ping
was the last outstanding one).

No new tests: pure glue over connect_lan_first, which has its own
unit coverage.
This commit is contained in:
Omar Sobh
2026-07-14 12:10:54 -07:00
parent fa863fdc7d
commit cf12554128
+27 -3
View File
@@ -104,6 +104,13 @@ enum Cmd {
/// Peer's RPC socket. Typically gossip_port + 1.
#[arg(long)]
rpc_addr: SocketAddr,
/// Phase 8c/8d: optional Tailscale RPC socket for
/// LAN-first-with-fallback routing. See `cluster-peer-status`.
#[arg(long)]
tailscale_addr: Option<SocketAddr>,
/// LAN probe deadline (ms) when `--tailscale-addr` is set.
#[arg(long, default_value_t = 200)]
lan_probe_ms: u64,
/// Payload to send. Echoed back with a "pong:" prefix.
#[arg(long, default_value = "hello")]
payload: String,
@@ -345,9 +352,11 @@ async fn main() -> Result<()> {
name,
peer,
rpc_addr,
tailscale_addr,
lan_probe_ms,
payload,
tls_dir,
} => cmd_cluster_ping(&name, &peer, rpc_addr, &payload, tls_dir.as_deref()).await?,
} => cmd_cluster_ping(&name, &peer, rpc_addr, tailscale_addr, lan_probe_ms, &payload, tls_dir.as_deref()).await?,
Cmd::ClusterGc { evict_to_gb } => cmd_cluster_gc(&cfg, evict_to_gb).await?,
Cmd::ClusterScrub { verbose } => cmd_cluster_scrub(&cfg, verbose).await?,
Cmd::ClusterRepair {
@@ -1072,10 +1081,12 @@ async fn cmd_cluster_ping(
name: &str,
peer: &str,
rpc_addr: SocketAddr,
tailscale_addr: Option<SocketAddr>,
lan_probe_ms: u64,
payload: &str,
tls_dir: Option<&std::path::Path>,
) -> Result<()> {
use cluster::transport::{ping, NodeIdentity, QuicClient};
use cluster::transport::{ping, ConnectRoute, NodeIdentity, QuicClient};
// Two identity paths:
// 1. `--tls-dir` present → load persisted PEM. The peer must have
@@ -1093,7 +1104,20 @@ async fn cmd_cluster_ping(
};
let client = QuicClient::new("0.0.0.0:0".parse()?, id_self)?;
let conn = client.connect(rpc_addr, peer).await?;
// Phase 8: LAN-first with optional tailnet fallback. Zero flag
// = identical to pre-8 single-addr dial.
let (conn, route) = client
.connect_lan_first(
peer,
Some(rpc_addr),
tailscale_addr,
std::time::Duration::from_millis(lan_probe_ms),
)
.await?;
match route {
ConnectRoute::Lan(a) => println!("route: LAN ({a})"),
ConnectRoute::Tailscale(a) => println!("route: tailnet ({a})"),
}
let response = ping(&conn, payload.as_bytes()).await?;
println!("→ sent: {}", payload);
println!("← recv: {}", String::from_utf8_lossy(&response));