跳转至

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 才查内容」是条件探测,用 shell if 保留,不退化为无条件;
  • 逐包 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 + --drift rc=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 同步,请勿在站点侧修改)