fix: expose user tool path in ssh scripts
This commit is contained in:
+20
-1
@@ -146,6 +146,15 @@ exec /root/unidesk/scripts/tran "$@"
|
||||
|
||||
`tran` 同样遵守 route/operation 解析器;route 后面的第一个 token 不是原生 ssh 命令字符串。不要写 `tran G14:/root/hwlab sh -lc '...'`,因为 `sh` 会被解析为 stdin script helper 的别名,`-lc` 会变成不受支持的 script 选项。带变量展开、管道、重定向或多条命令的远端逻辑,默认使用 `tran G14:/root/hwlab script <<'SCRIPT'`;默认 `script` 走目标节点 `/bin/sh`,并继承 provider-gateway/G14 已长期化的 proxy 环境。需要临时单步执行一行远端 shell 逻辑、且不想先创建脚本文件或 heredoc 时,优先使用 `tran G14:/root/hwlab script -- 'sed -n "1,20p" a && sed -n "1,20p" b'`,CLI 会把单个字符串放进目标节点的 `sh -c`,第二个 `sed`、管道和重定向都会留在远端;等价 `shell '<command>'` 仍保留为显式 shell operation。`script` 和 `shell` helper 会在用户 shell 文本前注入一个极小的 POSIX 兼容 `printf` wrapper,使 `printf "--- section ---\n"` 这类高频排障分隔标题在 dash/sh 与 bash 下行为一致;direct argv 形态不注入该 wrapper。`script --` 后跟多个 token 时保持 direct argv,例如 `tran G14:/root/hwlab script -- sed -n '1,20p' AGENTS.md`。只有脚本确实使用 `pipefail`、数组、`[[ ... ]]` 等 bash 专有语义时才加 `--shell bash`,不能把 `--shell bash` 当作 proxy 修复手段。单进程命令才直接写成 argv,例如 `tran G14:/root/hwlab git status --short --branch`。遇到分布式开发摩擦时,优先补强 `tran` 的 route/operation、stdin helper 或目标节点环境,并把稳定解法写回长期参考文档,不要退回多层 shell 字符串拼接。
|
||||
|
||||
非交互 `ssh`/`tran` 不是登录 shell,不能依赖 `.bashrc`、`.profile` 或交互 alias。
|
||||
CLI 会在 Host route、workspace route、k3s 控制面脚本和 pod route 的 shell/script helper
|
||||
前统一注入用户级工具 PATH:`$HOME/.bun/bin`、`$HOME/.local/bin`、`$HOME/bin`
|
||||
和 `/root/.bun/bin`。因此 G14 这类节点只要已经安装了 `/root/.bun/bin/bun`,
|
||||
`tran G14:/root/hwlab-v02 script -- 'bun --version'` 应该直接可用,
|
||||
不需要在任务里硬写绝对路径。direct argv 不经过 shell 初始化;如果某个 direct argv 工具找不到,
|
||||
优先改用 `script -- '<command>'` 或补强 CLI 的 argv PATH 处理,
|
||||
不要在业务脚本里长期散落绝对路径 workaround。
|
||||
|
||||
本地 shell 运算符不是 `tran` 可以拦截的内容。`tran G14:/root/hwlab sed -n '1,20p' AGENTS.md && sed -n '1,20p' docs/reference/g14.md` 会先由 master server 的本地 shell 拆成两个命令,只有第一个 `sed` 进入 G14,第二个 `sed` 会在 master server 当前目录执行。需要把两个命令都放到目标节点时,必须写成 `tran G14:/root/hwlab script -- 'sed -n "1,20p" AGENTS.md && sed -n "1,20p" docs/reference/g14.md'`,或者用 `tran G14:/root/hwlab script <<'SCRIPT'` 把多行脚本送到远端。
|
||||
|
||||
`tran` 不做本地 provider/plane 串行锁;本地目录锁不是 G14 原生 k3s/Tekton/GitOps 的业务协调机制,stale lock 会阻塞所有后续短查询。以后不要在 `tran` wrapper 里恢复本地锁。业务并发、发布互斥和 rollout 协调必须交给 k8s/Tekton/Argo/Lease 等原生运行面机制;若 provider session allocator 需要限流,应在服务端实现带 TTL 的队列或 lease,而不是在客户端加目录锁。
|
||||
@@ -219,7 +228,17 @@ printf 'import sys\nprint(sys.argv)\n' | bun scripts/cli.ts ssh D601 py foo '--b
|
||||
|
||||
`ssh <providerId> py` 的附加参数是脚本参数,不是 Python 解释器参数;如需 `-m`、`-X` 或多条 shell 命令,仍使用原始远端命令入口。为了保证 CLI 输出及时可见,helper 固定采用“临时文件 + `python3 -u`”模式;provider 命令模式不分配 TTY,因此脚本内容不应被远端回显。
|
||||
|
||||
如果远端逻辑需要 shell 特性,不要再把整段脚本作为原生 ssh-like 命令字符串传入。正式入口是 `bun scripts/cli.ts ssh D601 script`,脚本正文从 stdin 进入;CLI 会把本地 stdin 直接送到远端 `sh -s --`,`--shell bash` 可切换为 bash,`--` 后的内容会作为脚本参数传入。`script`/`shell` helper 会在用户脚本文本前注入兼容前缀,让 `printf "--- section ---\n"` 这类分隔标题不再因目标 `/bin/sh` 方言失败;已有 `printf '%s\n' value`、`printf -- ...` 和 bash 的 `printf -v` 仍按原语义工作。临时单步执行优先用 quoted heredoc;只有命令很短、明确希望一行内完成时才用 `script -- '<command && command>'`,它会把单个字符串按远端 shell one-liner 执行且不等待 stdin;复用脚本时才用 `< script.sh` 文件重定向。`script -- <多个 argv>` 仍是 direct argv,不经过远端 shell,适合 `script -- sed -n '1,20p' file`。典型用法:
|
||||
如果远端逻辑需要 shell 特性,不要再把整段脚本作为原生 ssh-like 命令字符串传入。正式入口是
|
||||
`bun scripts/cli.ts ssh D601 script`,脚本正文从 stdin 进入;CLI 会把本地 stdin 直接送到远端
|
||||
`sh -s --`,`--shell bash` 可切换为 bash,`--` 后的内容会作为脚本参数传入。
|
||||
`script`/`shell` helper 会在用户脚本文本前注入用户级工具 PATH 和兼容前缀,
|
||||
让 `bun`、`tsx` 等用户级工具在非交互 shell 中可见,也让 `printf "--- section ---\n"`
|
||||
这类分隔标题不再因目标 `/bin/sh` 方言失败;已有 `printf '%s\n' value`、`printf -- ...`
|
||||
和 bash 的 `printf -v` 仍按原语义工作。临时单步执行优先用 quoted heredoc;
|
||||
只有命令很短、明确希望一行内完成时才用 `script -- '<command && command>'`,
|
||||
它会把单个字符串按远端 shell one-liner 执行且不等待 stdin;
|
||||
复用脚本时才用 `< script.sh` 文件重定向。`script -- <多个 argv>` 仍是 direct argv,
|
||||
不经过远端 shell,适合 `script -- sed -n '1,20p' file`。典型用法:
|
||||
|
||||
```bash
|
||||
cat <<'SCRIPT' | bun scripts/cli.ts ssh D601 script --shell bash -- alpha
|
||||
|
||||
+18
-3
@@ -89,6 +89,16 @@ const defaultSshSlowWarningMs = 10_000;
|
||||
const defaultSshRuntimeTimeoutMs = 60_000;
|
||||
const maxSshRuntimeTimeoutMs = 60_000;
|
||||
export const sshShellCompatibilityPrelude = 'printf(){ if [ "${1+x}" = x ] && [ "$1" = "-v" ] && [ -n "${BASH_VERSION:-}" ]; then command printf "$@"; return $?; fi; if [ "${1+x}" = x ] && [ "$1" = "--" ]; then shift; fi; command printf -- "$@"; }';
|
||||
export const sshUserToolPathPrelude = [
|
||||
'for unidesk_path_dir in "$HOME/.bun/bin" "$HOME/.local/bin" "$HOME/bin" "/root/.bun/bin"; do',
|
||||
' [ -d "$unidesk_path_dir" ] || continue',
|
||||
' case ":$PATH:" in',
|
||||
' *":$unidesk_path_dir:"*) ;;',
|
||||
' *) PATH="$unidesk_path_dir:$PATH" ;;',
|
||||
" esac",
|
||||
"done",
|
||||
"export PATH",
|
||||
].join("\n");
|
||||
const k3sResourceKindAliases = new Set(["pod", "po", "pods", "deployment", "deploy", "deployments", "statefulset", "sts", "daemonset", "ds", "job", "jobs"]);
|
||||
const k3sPodRoutePrefixes = ["pod:", "po:", "pods:"];
|
||||
const legacyK3sOperationRouteSegments = new Set([
|
||||
@@ -1857,12 +1867,16 @@ function k3sScriptShell(value: string, option: string): string {
|
||||
return value;
|
||||
}
|
||||
|
||||
function shellScriptPrelude(): string {
|
||||
return `${sshUserToolPathPrelude}\n${sshShellCompatibilityPrelude}`;
|
||||
}
|
||||
|
||||
function shellScriptWithCompatibility(command: string): string {
|
||||
return `${sshShellCompatibilityPrelude}\n${command}`;
|
||||
return `${shellScriptPrelude()}\n${command}`;
|
||||
}
|
||||
|
||||
function shellScriptStdinPrefix(): string {
|
||||
return `${sshShellCompatibilityPrelude}\n`;
|
||||
return `${shellScriptPrelude()}\n`;
|
||||
}
|
||||
|
||||
function buildShellCommand(args: string[]): ParsedSshArgs {
|
||||
@@ -1963,7 +1977,8 @@ function remoteToolBootstrapCommand(helpers: readonly SshHelperName[] = []): str
|
||||
|
||||
export function wrapSshRemoteCommand(command: string | null, helpers: readonly SshHelperName[] = []): string {
|
||||
const bootstrap = remoteToolBootstrapCommand(helpers);
|
||||
const prefix = bootstrap.length > 0 ? `${bootstrap}; ` : "";
|
||||
const prelude = [sshUserToolPathPrelude, bootstrap].filter((part) => part.length > 0).join("; ");
|
||||
const prefix = prelude.length > 0 ? `${prelude}; ` : "";
|
||||
if (command === null) return `${prefix}exec "\${SHELL:-/bin/bash}" -l`;
|
||||
return `${prefix}stty -echo 2>/dev/null || true; ${command}`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user