# SSH client primitives — extracted from cli/components.nu (ADR-026 slice 2a-iii). # Get SSH connection info for a server (user, key path, host) from servers.ncl. export def comp-server-ssh-info [ws_root: string, infra: string, server: string]: nothing -> record { let servers_path = ($ws_root | path join "infra" $infra "servers.ncl") if not ($servers_path | path exists) { return { user: "root", key: "", host: $server } } let raw = (ncl-eval-soft $servers_path (default-ncl-paths $ws_root) null) if ($raw == null) { return { user: "root", key: "", host: $server } } let srv = ($raw | get -o servers | default [] | where {|s| ($s.hostname? | default "") == $server } | get 0?) let user = if ($srv | is-not-empty) { ($srv | get -o installer_user | default "root") } else { "root" } let key_raw = if ($srv | is-not-empty) { ($srv | get -o ssh_key_path | default "") } else { "" } let key = if ($key_raw | is-not-empty) { $key_raw | path expand } else { "" } let state_path = ($ws_root | path join "infra" $infra ".servers-state.json") let srv_state = if ($state_path | path exists) { $state_path | open | get -o $server | default {} } else { {} } let host = if ($srv | is-not-empty) { let np = ($srv | get -o networking.public_ip | default "") if ($np | is-not-empty) { $np } else { # floating_ip is a Hetzner API assignment name, not an SSH target. # Always use public_ip from state for SSH — the server's primary reachable address. let state_ip = ($srv_state | get -o public_ip | default "") if ($state_ip | is-not-empty) { $state_ip } else { $server } } } else { $server } { user: $user, key: $key, host: $host } } # Run a command on a remote host via SSH (with or without explicit identity file). # ConnectTimeout bounds the connect phase; ServerAlive (5s × 3) tears down a # session that goes silent after connect so a stalled remote command can never # hang the caller indefinitely. Callers that run kubectl wrap it in `timeout`. export def comp-ssh-run [user: string, key: string, host: string, cmd: string]: nothing -> record { let opts = [ -o ConnectTimeout=10 -o ServerAliveInterval=5 -o ServerAliveCountMax=3 -o BatchMode=yes ] if ($key | is-not-empty) { do { ^ssh -i $key ...$opts $"($user)@($host)" $cmd } | complete } else { do { ^ssh ...$opts $"($user)@($host)" $cmd } | complete } }