跳转至

SOP — vncserver 只读探测批量化(拼 shell + 探测缓存 + 连接复用)

主题目录:services/vncserver/vnc-server-deploy/probe_batch_20261008/|执行日期:2026-10-08|类型:C 类(改实现体) 触发:把「只读探测批量化」推广到其它工程时,vncserver 是三件套全缺的一个(无连接复用、无拼 shell、无缓存)

1. 背景

侦查结论(file:line 复核):

事实 证据
目标单主机 192.168.31.28(hpc-submit) config/site.yaml:5
自研 SSHRunner,每次 .run() 都 subprocess 新起一个 ssh 进程 utils/common.py:71-88
pre_check 逐条探测(os-release/uname/getenforce/uname -r/repo/cmds/sssd/free/df/ss…) deployer.py:96-197
sync_status 逐条 sha256 / 逐包 rpm -q / systemctl deployer.py:240-359
无连接池、无 (host,cmd) 缓存、无拼 shell 全工程 grep 无命中

因是单主机,「主机间并发」不适用;收益来自 ① 同主机多条拼一段 shell ② 探测缓存 ③ ssh 连接复用。

2. 目标

# 目标 判据
1 SSHRunner 支持「一条 shell 取回多条只读探测」且退出码不丢 真机冒烟:exit 3 → rc=3、test -f 不存在 → rc=1
2 SSHRunner 增加 (命令原文) 探测缓存,变更后自动失效 离线自测:命中不再下发;invalidate 后重新下发
3 ssh 连接复用(ControlMaster) _ssh() 含 ControlMaster/ControlPath/ControlPersist
4 pre_check / sync_status 改走批量 + 缓存 上机 plan:墙钟下降、变更清单逐条一致

3. 前置条件

  • 工程根 /home/rain/Documents/services/vncserver/vnc-server-deploy;
  • 到 192.168.31.28 的 root 免密(实测 ssh -o BatchMode=yes 返回 OK);
  • 变更前完成 5.1 备份;验证全程只读(plan / precheck / drift)。

4. 影响范围

项 内容
变更对象 utils/common.py(SSHRunner)、deployer.py
改的是什么 只读探测的打包方式(拼 shell / 缓存 / 连接复用);判定表达式、变更清单顺序与内容、变更类命令均未动
是否停服 否;验证只读
回滚风险 低:改动集中在 _pkg_installed / _xfce_ready / _ldap_endpoint / _ports_in_use + pre_check / sync_status / _step_packages

5. 分步操作

5.1 备份

TOP=/home/rain/Documents/services/vncserver/vnc-server-deploy/probe_batch_20261008
mkdir -p "$TOP/backup"
cd /home/rain/Documents/services/vncserver/vnc-server-deploy
cp -a deployer.py utils/common.py "$TOP/backup/"

5.2 utils/common.py:SSHRunner 三件事

本节与 5.3 是实现体源码改动(改代码,不是在机器上跑的命令),故以「改动点 + 等价语义」呈现; 手工复现的唯一正确方式是 5.5 的「用 backup/ 旧版覆盖跑一轮」对照。 实现体:utils/common.py、deployer.py(实际执行以实现体为准)。

# ① 连接复用(_ssh 内)
#   -o ControlMaster=auto -o ControlPath=/tmp/vncdeploy-ssh-<target>-<port> -o ControlPersist=120s
# ② 探测缓存
#   self._cache: Dict[命令原文, Result];run_cached(cmd) 命中即不下发;invalidate() 清空
# ③ 批量探测
#   probe({键: 只读命令}) -> {键: Result}:拼一段 shell 一次往返,并回填缓存

两个必须知道的坑(本主题实测踩到并修掉): 1. 退出码回传必须用独立整行标记 —— 初版写成 printf '@@rc_键 %s\n' "$?",与 _parse_kv 的「@@键 整行」约定不符,导致 rc 段被并入值段(真机表现为 exit 3 → rc=0)。 改为:命令 → __rc=$? → echo '@@rc_键' → echo "$__rc"。 2. 每条探测命令必须用子 shell ( … ) 包裹 —— 否则命令里的 exit 会终止整段 shell, 后续段与 rc 全部丢失。 3. 附带:探测命令若不输出换行(如 curl -w '%{http_code}'),会把 @@rc_ 标记粘进取值 (harbor 工程在同类改造中实际踩到)。

5.3 deployer.py:只读探测改走批量 + 缓存

# pre_check:环境契约 4 条 → 1 条 probe;包源/关键命令/SSSD/内存/磁盘 → 1 条 probe
# _pkg_installed / _xfce_ready / _ldap_endpoint / _ports_in_use → run_cached(同文本才命中)
# _installed_packages:一次 `rpm -q --qf '%{NAME}\n' p1 p2 …`(注意 %%{NAME} 转义)
# sync_status / _step_packages:包循环改 _installed_packages
# _maybe:变更后 self.r.invalidate();put_text 同理

5.4 离线自测

cd /home/rain/Documents/services/vncserver/vnc-server-deploy
python3 -m py_compile deployer.py utils/common.py && echo COMPILE_OK
python3 probe_batch_20261008/selftest.py      # → VNC_PROBE_CACHE_SELFTEST_OK

5.5 上机新旧对照(只读 plan)

mkdir -p /tmp/vncnew && cp deployer.py /tmp/vncnew/ && cp utils/common.py /tmp/vncnew/   # 先存新版!
python3 deployer.py plan > /tmp/vnc_new.log 2>&1
cp probe_batch_20261008/backup/deployer.py . && cp probe_batch_20261008/backup/common.py utils/common.py
python3 deployer.py plan > /tmp/vnc_old.log 2>&1
cp /tmp/vncnew/deployer.py . && cp /tmp/vncnew/common.py utils/common.py
cmp -s deployer.py /tmp/vncnew/deployer.py && cmp -s utils/common.py /tmp/vncnew/common.py && echo RESTORE_OK

⚠️ 务必先 cp 新版到 /tmp 再覆盖 —— 本次首轮对照漏了这一步,导致新版被旧版覆盖、需按本章重放改动。

6. 验证

验证一:离线自测 —— VNC_PROBE_CACHE_SELFTEST_OK(12 项):probe 一条 shell、段值与 rc 正确、 非 0 退出码传递、缓存命中/失效/关闭、文本不一致不命中、_ssh 含三个 Control* 参数。

验证二:真机 probe 冒烟(.28)

键 命令 实测 rc
osrel grep -E '^(ID\|VERSION_ID)=' /etc/os-release 0(值 ID="rocky" / VERSION_ID="9.8")
sssd systemctl is-active --quiet sssd 0
bad exit 3 3
missing test -f /no/such/file 1

验证三:上机 plan 新旧对照(2026-10-08)【已确认】

方案 墙钟 ms rc 待变更项
旧 16126 0 0
新 6011(-62.7%) 0 0

输出 diff:仅「日志文件名 / 报告文件名」的时间戳不同,业务内容逐条一致。还原校验 RESTORE_OK。

7. 回滚

cd /home/rain/Documents/services/vncserver/vnc-server-deploy
BAK=probe_batch_20261008/backup
cp -a $BAK/deployer.py . && cp -a $BAK/common.py utils/common.py

回滚后验证:py_compile + plan(墙钟回到 ~16 s、清单不变)。

8. 风险说明

风险 缓解
拼 shell 后退出码丢失 → 三态判定失真 用独立整行 @@rc_键 回传;真机验证 rc=3/1/0
探测命令含 exit 终止整段 shell 每段用子 shell ( … ) 包裹
探测命令不输出换行 → 标记粘连取值 docstring 写明;harbor 已实测踩到并修
缓存陈旧(变更后仍读旧值) _maybe / put_text 成功后自动 invalidate()
ControlPersist 残留 socket ControlPersist=120s 自动回收;socket 在 /tmp,重启即清
对照时覆盖丢失新版 SOP 5.5 强制「先 cp 新版到 /tmp」并 cmp 校验

附录 A 交付物清单

文件 说明
SOP.md 本文件
selftest.py 离线自测(12 项)
backup/deployer.py、backup/common.py 改造前快照
backup/README.md 备份台账
变更的工程文件 deployer.py、utils/common.py

附录 B 与共享库的关系

本例是自研 SSH 层(subprocess 调系统 ssh),与共享库 base_module / ssh_executor 无关, 故三件套在本工程需自行实现;同类能力在共享库侧的对应物是 BaseModule.query_on_host / probe_per_host(本次同步新增)与 SSHExecutor.run_on_all。

附录 C RUNBOOK 判定

本工程已有 docs/RUNBOOK.md(覆盖 VNC 服务的日常使用与排障)。本次变更只改只读探测的打包方式 (拼 shell / 缓存 / 连接复用),服务的用法、交付物形态、配置文件与命令均未变, 故无需更新 RUNBOOK;若日后探测行为对使用者可见(如新增子命令或改变输出),须同步更新它。


来源:/home/rain/Documents/services/vncserver/vnc-server-deploy/probe_batch_20261008/SOP.md | 最后更新:2026-10-08 11:44(由 build/sync.py 同步,请勿在站点侧修改)