SOP — 阶段2 node-env / 阶段3-6 install 探测批量化(消除最后一处逐项与串行)¶
主题目录:
lsf_ins/lsf_probe_batch3_20261007/|执行日期:2026-10-07|类型:C 类(改实现体) 前序:lsf_probe_batch_20261007(工程侧三处)、shared_precheck_batch_20261007(共享库底座)、lsf_probe_batch2_20261007(precheck 域名检查 / 阶段0 去 N²)
1. 背景¶
第三轮收尾后,--drift 仍有 62.3 s / 159 条命令。逐阶段归因(按日志顺序归属)发现两块占了 71%:
| 阶段 | 命令数 | 耗时 | 结构 |
|---|---|---|---|
| 阶段2 node-env | 78 | 30.4 s | 每台串行 13 条:逐包 rpm -q + sssd.conf(2) + sssd + getent + authselect + oddjobd |
| 阶段3-6 install | 40 | 14.0 s | 每台 8 条(lsf.cluster / lsf.conf 四项加固 / entitlement / hostsetup / profile.d) |
两处都还是老写法(for host: for item: ssh.run(...)),既没拼 shell 也没主机间并发。
ops-execution-efficiency 的口径:同一主机的多条只读检查必须拼成一条 shell,
「优先找自带批量参数的工具形式(rpm -q p1 p2 而非 for p; do rpm -q $p; done)」。
2. 目标¶
| # | 目标 | 判据 |
|---|---|---|
| 1 | 两处 probe() 改为每主机一条 shell + 主机间并发 |
--drift 命令数 159 → 52;两阶段 78/40 → 6/5 |
| 2 | 逐包 rpm -q 改为一次多包查询 |
缺包判据不变(--qf '%{NAME}' 只列已安装) |
| 3 | probe_state 依赖的退出码语义不失真 |
用 if …; then echo active; else echo inactive; fi 还原 |
| 4 | 判定语义完全不变 | --drift 模块级输出逐行一致、20 阶段无漂移 |
3. 前置条件¶
- 工程根
/home/rain/Documents/LSF/lsf_ins,deploy/lsf/.venv可用; - 6 台节点(
.23–.28)SSH 凭据沿用deploy/lsf/config/credentials.yaml(600); - 变更前完成 5.1 备份;验证以
--drift为主(只读)。
4. 影响范围¶
| 项 | 内容 |
|---|---|
| 变更对象 | stages/node_env.py、stages/lsf_install.py(2 文件) |
| 改的是什么 | 只改 probe() 的探测方式;判定表达式、消息文案、execute()/validate() 一律不动 |
| 是否停服 | 否;验证全程只读 |
| 窗口期 | 无要求 |
5. 分步操作¶
5.1 备份(高危前置)¶
TOP=/home/rain/Documents/LSF/lsf_ins/lsf_probe_batch3_20261007
STAMP=$(date +%Y%m%d-%H%M%S)
mkdir -p "$TOP/backup/lsf_ins/deploy/lsf/stages"
cd /home/rain/Documents/LSF/lsf_ins/deploy/lsf
for f in stages/node_env.py stages/lsf_install.py; do
cp -a "$f" "$TOP/backup/lsf_ins/deploy/lsf/$f.bak.$STAMP"
done
预期:2 个 .bak.20261007-210338。坑:必须在任何编辑之前完成。
5.2 node_env.probe():每主机一条 shell¶
# 每台主机一次往返(主机间并发):
rpm -q --qf '%{NAME}\n' <包1> <包2> … 2>/dev/null || true # 多包一次查询
stat -c '%a' /etc/sssd/sssd.conf 2>/dev/null || true
if [ "$(stat -c '%a' /etc/sssd/sssd.conf 2>/dev/null)" = "600" ]; then
grep -c <search_base> /etc/sssd/sssd.conf 2>/dev/null || true # 保留原条件探测
fi
if systemctl is-active sssd >/dev/null 2>&1; then echo active; else echo inactive; fi
authselect current 2>/dev/null || true
if systemctl is-active oddjobd >/dev/null 2>&1; then echo active; else echo inactive; fi
getent passwd <probe_user> || true
坑(必须留痕):
- 原
probe_state(host, "systemctl is-active sssd")依赖退出码(非 0 即 pending)。probe_hosts_kv只回传 stdout,故用if …; then echo active; else echo inactive; fi把退出码语义还原成可见输出——不能直接写systemctl is-active sssd || true(那样永远为 0); sssd.conf的「仅当权限 600 才查内容」是条件探测,用 shellif保留,不退化为无条件;- 逐包
rpm -q→rpm -q --qf '%{NAME}\n'多包一次;缺失者对 stderr 报错,故 「缺失 = 配置清单 − stdout 命中」; - 整机不可达(host 级 rc=-1)→ 全项
unknown;包项按原语义记pending+ 全部包列入_missing_pkgs(原probe_state对连接层失败返回 unknown,调用方!= "done"即计 missing)。
5.3 lsf_install.probe():节点侧每主机一条 shell¶
# 每台主机一次往返:8 项加固判据全部拼进同一条 shell
test -d <machdep>/etc && test -f <cluster_file> && grep -c <node_name> <cluster_file> || true
test -f <lsf_conf> && grep -c 'LSF_RSH=rsh' <lsf_conf> || true
test -f <lsf_conf> && grep -c 'LSF_ADMINS' <lsf_conf> || true
test -f <lsf_conf> && grep -c 'LSF_STRICT_CHECKING=N' <lsf_conf> || true
test -f <lsf_conf> && grep -c '^LSF_ROOT_USER=Y' <lsf_conf> || true
test -f <entitlement_file> && echo yes || echo no
systemctl cat lsfd.service 2>/dev/null | grep -qF <machdep>/etc/lsf_daemons && echo yes || echo no
test -f /etc/profile.d/lsf.sh && echo yes || echo no
坑:操作机侧(解压/install.config/冒烟标记)全是本地文件判断,本次不动;
只改节点侧。判据「grep -c 结果非 0 非空即 done」与原逐条版一致。
5.4 离线自测(上机前)¶
cd /home/rain/Documents/LSF/lsf_ins/deploy/lsf
.venv/bin/python -m py_compile stages/node_env.py stages/lsf_install.py && echo COMPILE_OK
.venv/bin/python ../lsf_probe_batch3_20261007/selftest.py
预期:COMPILE_OK + BATCH3_SELFTEST_OK。自测用桩 ssh(同时服务「批量 shell」与「逐条命令」),
不连任何主机;核心是第 1、2 组的等价性比对——把 backup 版模块以模块方式载入,
与新版在同一份模拟状态下跑 probe(),states 逐条比对。
5.5 上机验证(只读)¶
cd /home/rain/Documents/LSF/lsf_ins/deploy/lsf
LOG=logs/lsf_deploy.log; S0=$(wc -l < "$LOG"); T0=$(date +%s.%N)
.venv/bin/python main.py --config config/lsf_deploy.yaml --drift > /tmp/drift.txt 2>&1
T1=$(date +%s.%N)
echo "wall=$(awk "BEGIN{printf \"%.1f\", $T1-$T0}")s cmds=$(tail -n +"$((S0+1))" "$LOG" | grep -c '命令执行完成')"
6. 验证¶
验证一:语义等价(核心)
- 离线:node_env 与 lsf_install 的新旧 probe() states 逐条完全一致(覆盖 缺包 / sssd.conf
权限非 600 / 权限 600 但内容缺 base / sssd 与 oddjobd 未运行 / getent 解析不到 / authprofile 不符 /
各加固项命中与未命中 / hostsetup 指向旧平台 / 整机不可达);
- 上机:--drift 的模块级输出逐行一致(差异仅报告文件名时间戳),rc=0、20 阶段全无漂移、
0 探测失败。
验证二:命令数与墙钟【已确认】
| 子命令 / 阶段 | 本轮前 | 本轮后 | 降幅 |
|---|---|---|---|
--drift 合计 |
159 条 / 62.3 s | 52 条 / 20.4 s | 命令 -67.3%、墙钟 -67.3% |
| ├ 阶段2 node-env | 78 条 / 30.4 s | 6 条 / 2.3 s | -92% / -92% |
| └ 阶段3-6 install | 40 条 / 14.0 s | 5 条 / 1.5 s | -87.5% / -89% |
| 其余 8 个阶段 | 41 条 / 17.9 s | 41 条 / 16.6 s | 不变(已到「每台一条」) |
相对最初基线(四轮累计):--drift 327 条 / 131.8 s → 52 条 / 20.4 s
(命令 -84.1%、墙钟 -84.5%)。
验证三:离线命令数对照(4 台主机、同一模拟状态):两个 probe 均为 32 → 4 条。
验证四:幂等 —— --drift 复跑 rc=0、无漂移、命令数不变。
失败判断:states 出现任何差异,或 --drift 出现漂移 / 探测失败,或 py_compile / 自测失败
→ 停止,按第 7 章回滚。
7. 回滚¶
- 备份位置:
lsf_probe_batch3_20261007/backup/lsf_ins/deploy/lsf/,台账见本主题backup/README.md。 - 回滚步骤:
cd /home/rain/Documents/LSF/lsf_ins
BAK=lsf_probe_batch3_20261007/backup/lsf_ins/deploy/lsf
cd deploy/lsf
for f in stages/node_env.py stages/lsf_install.py; do cp -a "../../$BAK/$f".bak.* "$f"; done
- 回滚后验证:
py_compile+--driftrc=0 无漂移(命令数回到 159 量级)。 - 回滚触发条件:任一 states 差异;
--drift出现漂移或探测失败;自测失败;命令数未下降。
8. 风险说明¶
| 风险 | 缓解 |
|---|---|
systemctl is-active 的退出码语义丢失(写成 \|\| true 恒为 0) |
用 if …; then echo active; else echo inactive; fi 还原;离线自测含 sssd/oddjobd 未运行的用例并通过 |
| 条件探测(权限 600 才查内容)被退化为无条件 | shell if 保留;离线断言「权限非 600 → pending」通过 |
rpm -q 多包形式与逐包判定不等价 |
--qf '%{NAME}\n' 只列已安装包名;离线含缺包用例并通过 |
| 整机不可达时条目状态与原实现不一致 | 逐项对齐(包项 pending + 全 missing、其余 unknown),离线含 down 主机用例通过 |
| 拼接后 stdout 变长进日志 | 单条 stdout 由 ssh_executor 截到 200 字符;换取一次往返 |
lsf_install 的操作机侧被误改 |
本次只改节点侧;操作机侧(解压/install.config/冒烟标记)零改动 |
附录 A 交付物清单¶
| 文件 | 说明 |
|---|---|
SOP.md |
本文件 |
selftest.py |
离线自测(2 组等价性比对 + 命令数对照,桩 ssh 不连主机) |
backup/lsf_ins/deploy/lsf/** |
2 个改造前文件快照 |
backup/README.md |
备份台账 |
| 变更的工程文件 | deploy/lsf/stages/node_env.py、deploy/lsf/stages/lsf_install.py |
附录 B 剩下的(未纳入本轮)¶
| 项 | 说明 |
|---|---|
| 其余阶段 | up(4) / tune(3) / health(4) / user-sync(5) / submit(10) / local-scratch(3) —— 均已到「每台一条或更少」,再压收益 < 0.5 s/处,按停手判据不再动 |
user-sync(5 条 / 1.2 s) 与 submit(10 条 / 5.3 s) |
条数已低,但单条偏慢(0.5 s/条),属命令自身成本 |
derive_system_disks()(lsblk) |
仍逐主机一条独立命令(结构化 pairs + 自带二级缓存) |
| 连接数自报 | 工程仍未调 connection_pool.shutdown(),无「新建连接 N 次」输出;落点在编排层(deployer.py),非 BaseModule.run()(--drift 不经过 run()) |
| 其它工程 | samba_ins / kvm / harbor / eda_tools_ins / lustre_ins(缓存项) / vnc-server-deploy,模板见 lsf_probe_batch_20261007 SOP 附录 C |
来源:
/home/rain/Documents/LSF/lsf_ins/lsf_probe_batch3_20261007/SOP.md| 最后更新:2026-10-07 21:24(由build/sync.py同步,请勿在站点侧修改)