# Cluster kube-apiserver access resolution — extracted from cli/components.nu (ADR-026 slice 2a-iii). use tools/nickel/process.nu [comp-ncl-export] use domain/workspace/resolve.nu [comp-state-server comp-ws-path comp-ws-infra] use platform/clients/ssh.nu [comp-server-ssh-info comp-ssh-run] # Resolve how to reach the cluster's kube-apiserver for an infra. # provisioning NEVER runs kubectl locally: the API server is reachable only from # the control-plane node. The SSH host and remote kubectl invocation are declared # in settings.cluster_access (ssh_host + remote_kubectl). When unset, fall back to # the first server present in the state file and `k0s kubectl`. export def comp-kubectl-access [ws_root: string, infra: string]: nothing -> record { let raw = (comp-ncl-export $ws_root $"infra/($infra)/settings.ncl") let s = ($raw | get -o settings | default {}) let ca = ($s | get -o cluster_access | default {}) # Operator-delegated workspaces (adr-002) own no cluster — they deploy onto a # target cluster. With no local cluster_access, resolve the target workspace's # access so kubectl reads hit the operator cluster's control-plane, not a CP # this workspace does not have. Guarded: a failed cross-workspace resolve # falls through to the local default rather than aborting the caller. let target_ws = ($s | get -o deployment_target | default {} | get -o target_cluster | default {} | get -o workspace | default "") if ($ca | is-empty) and ($target_ws | is-not-empty) { let delegated = (try { let tgt_root = (comp-ws-path $target_ws) if ($tgt_root | is-not-empty) and ($tgt_root != $ws_root) and ($tgt_root | path exists) { comp-kubectl-access $tgt_root (comp-ws-infra $tgt_root) } else { null } } catch { null }) if ($delegated != null) { return $delegated } } let host = ($ca | get -o ssh_host | default "") let kc = ($ca | get -o remote_kubectl | default "k0s kubectl") let resolved_host = if ($host | is-not-empty) { $host } else { let state_root = if (($ws_root | path join "infra" $infra ".provisioning-state.ncl") | path exists) { $ws_root | path join "infra" $infra } else { $ws_root } comp-state-server $state_root } # ws_root/infra identify the workspace that OWNS the resolved host, so callers # resolve SSH connection details (ip/user/key) from the right servers.ncl even # when access was delegated from an operator-delegated workspace. { host: $resolved_host, kubectl: $kc, ws_root: $ws_root, infra: $infra } } # Run a remote kubectl command via SSH using the infra's declared cluster_access. # Hard-bounded so it can never hang: ConnectTimeout caps the connect phase, # ServerAlive kills a half-dead session, and a remote `timeout` caps the kubectl # call itself. Returns the {exit_code, stdout, stderr} record from `complete`. export def comp-kubectl-ssh [ ws_root: string, infra: string, kargs: string, # kubectl arguments, e.g. "get pods -A -o json" --cmd-timeout: int = 20, # remote wall-clock cap on the kubectl invocation ]: nothing -> record { let access = (comp-kubectl-access $ws_root $infra) if ($access.host | is-empty) { return { exit_code: 1, stdout: "", stderr: "cluster_access.ssh_host unset and no server in state file" } } # Resolve SSH details from the workspace that owns the host (the operator # cluster when access was delegated), not necessarily the calling workspace. let info = (comp-server-ssh-info $access.ws_root $access.infra $access.host) let remote = $"export PATH=/usr/local/bin:/usr/bin:/bin:$PATH; timeout ($cmd_timeout) ($access.kubectl) ($kargs)" comp-ssh-run $info.user $info.key $info.host $remote }