provisioning-core/nulib/platform/clients/ssh.nu

53 lines
2.5 KiB
Text
Raw Normal View History

# 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
}
}