chore(stress): 加 waiter 远程更新脚本;修 cmp.py 的 docstring 格式

## deploy-waiter.sh:106 / 30 的 waiter 更新

现状(更新前):两台都是 8月27日构建的 /opt/waiter/waiter(11,388,177 字节),
以 root 跑 waiter-remote.service,配置指向 ws://192.168.2.60:9890/…

安全设计:
- 先备份旧二进制(`$BIN.bak-<时间戳>`),失败即回滚(脚本内自动)
- **只换二进制,不动 waiter.yaml**(配置由 deploy 后单独追加)
- **逐台更新并验证,不并行** —— 两台都连同一网关,同时重启会同时断链
- 106 走 admin+sudo、30 走 root
- 验证项:服务 active + 进程时长 + **配置 md5 未变**

用法:`check`(只读)/ `deploy <ip>`(需输 yes)/ `rollback <ip>`

## cmp.py:两处格式

docstring 的 `"""` 紧贴内容、以及函数段之间缺两个空行(PEP8)。纯格式,
无逻辑改动。
This commit is contained in:
JianFeeeee
2026-09-27 19:42:06 +08:00
parent 71934464cf
commit 20e5d917c3
3 changed files with 145 additions and 6 deletions

View File

@ -9,14 +9,14 @@ import (
)
var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetConsoleMode = kernel32.NewProc("GetConsoleMode")
procSetConsoleMode = kernel32.NewProc("SetConsoleMode")
procGetStdHandle = kernel32.NewProc("GetStdHandle")
)
const (
stdInputHandle = ^uint32(9) + 1 // -10
stdInputHandle = ^uint32(9) + 1 // -10
enableVirtualTerminalProcessing = 0x0004
enableProcessedOutput = 0x0001
enableWrapAtEOLOutput = 0x0002

136
deploy-waiter.sh Normal file
View File

@ -0,0 +1,136 @@
#!/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 ────"
ssh -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 -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 -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 -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 -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

View File

@ -90,13 +90,14 @@ def has_error(frames):
def tools_done(frames):
"""数出工具真正执行的个数(按 done-N 标记去重)。"""
""" 数出工具真正执行的个数(按 done-N 标记去重)。"""
blob = " ".join(frames)
return len({int(m.group(1)) for m in re.finditer(r"done-(\d+)", blob)})
# ---------------------------------------------------------------- 单轮测量
def measure(sock, key, marker, rounds):
"""连一次、跑 rounds 轮(每轮唯一输入)。
@ -128,6 +129,7 @@ def measure(sock, key, marker, rounds):
# ---------------------------------------------------------------- 并发轰炸
def blast(sock, key, conns, inputs, tag):
"""conns 条连接并发,每条连接连发 inputs 条输入。返回通过率。
@ -175,6 +177,7 @@ def blast(sock, key, conns, inputs, tag):
# ---------------------------------------------------------------- 主流程
def arg_int(pos, default, name):
"""解析位置参数为正整数;非法时给出可执行报错而不是裸 ValueError。"""
if pos >= len(sys.argv):