Files
HomeAgent/deploy-waiter.sh
JianFeeeee c022ac98cd fix(deploy): deploy-waiter 的 ssh 加 -n,否则「喂了 yes 却说已取消」
`do_check` 里的 ssh 会从 stdin 读,把后续 `read -p "确认更新"` 的输入吃掉 ——
于是 `bash deploy-waiter.sh deploy <ip> <<< "yes"` 里的 yes 被 ssh 消耗,
read 拿到空串,脚本静默走「已取消」分支。

症状极难定位:脚本本身完全正常、备份逻辑没问题,只是"明明喂了 yes"却
什么也没发生。5 处 ssh 统一加 -n。
2026-09-27 19:52:53 +08:00

140 lines
4.9 KiB
Bash
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/bin/bash
# waiter 远程更新(106 / 30)
#
# 现状(更新前):
# 两台都是 8月27日构建的 /opt/waiter/waiter(11,388,177 字节),
# 以 root 跑 waiter-remote.service,配置指向 ws://192.168.2.60:9890/...
# 进程已连续运行 1 天 7.5 小时、无掉线记录 ⇒ 本次是**预防性**更新:
# · 拿到 94c74b2 的设备桥修复(未 bind 时收到 ping 会关连接)
# · 版本对齐到内核 1.4.0(docs/git-branching.md 要求客户端与内核同步)
#
# 安全设计:
# · 先备份旧二进制,失败即回滚(trap 捕获)
# · 只换二进制,**不动** waiter.yaml
# · 逐台更新并验证,**不并行**(两台都连同一网关,同时重启会同时断链)
# · 验证项:进程活着 + 设备在网关侧注册成功
#
# 用法:
# bash deploy-waiter.sh check 只读检查
# bash deploy-waiter.sh deploy <ip> 更新指定一台
# bash deploy-waiter.sh rollback <ip> 回滚指定一台
set -uo pipefail
NEW=${NEW_WAITER:-/tmp/waiter-new}
SVC=waiter-remote.service
BIN=/opt/waiter/waiter
CFG=/opt/waiter/waiter.yaml
# 106 用 admin(需 sudo),30 用 root
ssh_of() {
case "$1" in
192.168.2.106) echo "admin@$1" ;;
192.168.2.30) echo "root@$1" ;;
*) echo "" ;;
esac
}
sudo_of() { [ "$1" = "192.168.2.106" ] && echo "sudo" || echo ""; }
say() { printf '\n\033[1m%s\033[0m\n' "$*"; }
info() { printf ' %s\n' "$*"; }
do_check() {
local ip=$1 t s
t=$(ssh_of "$ip"); [ -z "$t" ] && { info "未知主机: $ip"; return 1; }
s=$(sudo_of "$ip")
info "──── $ip ────"
# ★ -n:ssh 会从 stdin 读,若不截断会**吃掉后面 read 的输入**
# ("yes" 被 ssh 消耗 ⇒ read 拿到空 ⇒ 脚本静默取消)。
# 症状是"明明喂了 yes 却说已取消",极难定位。
ssh -n -o BatchMode=yes -o ConnectTimeout=8 "$t" "
echo -n ' 主机: '; hostname
echo -n ' 当前二进制: '; ls -la $BIN 2>/dev/null | awk '{print \$5\" 字节 \"\$6\" \"\$7\" \"\$8}'
echo -n ' 服务: '; systemctl is-active $SVC 2>/dev/null
echo -n ' 进程时长: '; ps -o etime= -p \$(pgrep -f 'waiter --daemon' | head -1) 2>/dev/null
echo -n ' 配置网关: '; grep -oE 'ws://[^\"]+' $CFG 2>/dev/null | head -1
echo -n ' 配置校验和: '; md5sum $CFG 2>/dev/null | cut -c1-32
" 2>&1
info " 新二进制: $NEW ($(stat -c %s "$NEW" 2>/dev/null) 字节)"
info " 新版本: $(/tmp/waiter-new --version 2>&1 | head -1)"
return 0
}
do_deploy() {
local ip=$1 t s
t=$(ssh_of "$ip"); [ -z "$t" ] && { info "未知主机: $ip"; return 1; }
s=$(sudo_of "$ip")
[ -f "$NEW" ] || { info "新二进制不存在: $NEW"; return 1; }
say "更新 $ip"
do_check "$ip"
echo
read -r -p "确认更新 $ip 的 waiter ? 输入 yes 继续: " ans
[ "$ans" = "yes" ] || { info "已取消"; return 1; }
# 备份 + 停服 + 替换 + 启服;失败即回滚
scp -q "$NEW" "$t:/tmp/waiter.new" || { info "上传失败"; return 1; }
info "已上传"
ssh -n -o BatchMode=yes -o ConnectTimeout=8 "$t" "
set -e
$s cp -a $BIN $BIN.bak-\$(date +%Y%m%d-%H%M%S)
echo BACKUP=\$(ls -t $BIN.bak-* | head -1)
$s systemctl stop $SVC
$s install -m 0755 /tmp/waiter.new $BIN
rm -f /tmp/waiter.new
$s systemctl start $SVC
" 2>&1 | tail -3
info "已替换并启动"
sleep 8
say "更新后验证 $ip"
local alive=false
for i in 1 2 3 4 5; do
if ssh -n -o BatchMode=yes -o ConnectTimeout=8 "$t" "systemctl is-active --quiet $SVC" 2>/dev/null; then
alive=true; break
fi
sleep 3
done
if [ "$alive" = true ]; then
info "✓ 服务 active"
ssh -n -o BatchMode=yes -o ConnectTimeout=8 "$t" "
echo -n ' 新二进制: '; ls -la $BIN | awk '{print \$5\" 字节\"}'
echo -n ' 进程时长: '; ps -o etime= -p \$(pgrep -f 'waiter --daemon' | head -1) 2>/dev/null
echo -n ' 配置未变: '; md5sum $CFG | cut -c1-32
" 2>&1
info "★ 请在网关侧确认设备已重新注册(/kernel 的 channels 应出现 device/<id>)"
else
info "✗ 服务未起来 —— 回滚"
do_rollback "$ip"
return 1
fi
}
do_rollback() {
local ip=$1 t s
t=$(ssh_of "$ip"); s=$(sudo_of "$ip")
say "回滚 $ip"
ssh -n -o BatchMode=yes -o ConnectTimeout=8 "$t" "
set -e
BAK=\$(ls -t $BIN.bak-* 2>/dev/null | head -1)
[ -n \"\$BAK\" ] || { echo '找不到备份'; exit 1; }
$s systemctl stop $SVC
$s install -m 0755 \"\$BAK\" $BIN
$s systemctl start $SVC
echo \"已回滚到 \$BAK\"
" 2>&1 | tail -2
sleep 5
info "服务: $(ssh -o BatchMode=yes "$t" "systemctl is-active $SVC" 2>/dev/null)"
}
case "${1:-check}" in
check)
for ip in 192.168.2.106 192.168.2.30; do say "检查 $ip"; do_check "$ip"; done
;;
deploy) do_deploy "${2:?用法: deploy <ip>}" ;;
rollback) do_rollback "${2:?用法: rollback <ip>}" ;;
*) echo "用法: $0 {check|deploy <ip>|rollback <ip>}"; exit 2 ;;
esac