跳转至

SOP — Lmod 站点扩展与模块收敛(SitePackage / slurm 模块退役 / 版本别名)

变更日期:2026-10-05 实施人:rain(Agent 执行) 状态:已完成,验收通过 归档目录:slurm_ins/lmod_site_package_20261005/ 触发来源:用户对 Lmod 的四点问询(提示块干扰 / slurm 模块是否该取消 / csh 补全 / 对标 EDA 行业标准)

1. 背景

上一轮(slurm_csh_profile_20261005)补齐了 csh 侧登录注入后,module avail 暴露出两处长期存在的不一致,另有一处使用习惯缺口:

  1. module avail 尾部固定打印一段提示块("If the avail list is too long consider trying: ...")。它来自 Lmod 的 messageDir/en.lua 的 avail 条目,由 StandardPackage.lua 注册的 msgHook 在 Hub:avail()(Hub.lua:1451)末尾输出,没有单独开关;且与模块列表同走 stderr,2>/dev/null 会把列表一起丢掉。
  2. Core/slurm/26.05.2.lua 已无存在价值:登录环境由 /etc/profile.d/slurm-path.{sh,csh}、slurm_configless.{sh,csh} 双轨注入,该模块只是重复前置 PATH(外加一个无人依赖的 SLURM_HOME),在 module avail 里纯属噪音。
  3. 同工具多版本无法不带版本加载:siemens/calibre/ 下并存 2026.1 与 2015.2_36.27,module load calibre 会因多重匹配报错。

2. 目标

  1. module avail 不再打印提示块,其余消息(尤其警告)格式与行为不变;
  2. 生成器不再产出 slurm 模块,并清理共享盘上遗留的 Core/slurm/ 目录(先备份);
  3. 健康检查与之对齐(不再借 slurm 模块做样本);
  4. module load calibre 命中默认版本 2026.1,另提供 calibre/latest 别名;
  5. 全程幂等:复跑零变更、全跳过;不停服、不重启任何 daemon。

3. 前置条件

  • root SSH 可达 6 台:控制 .16/.17、计算 .18/.19/.20、提交 .28;
  • 工程 .venv/ 与 config/slurm_deploy.yaml 就绪;Lmod 8.7.65(EPEL)已装;
  • /opt/modulefiles 为 NFS 共享挂载(192.168.31.249:/data/nfs/modulefiles),内容主节点为控制主节点 .16;
  • 执行前 squeue 必须为空(本实现体在 TaskProlog 变化时会重启 slurmd;本次 TaskProlog 无变化,实测未触发)。

4. 影响范围

项 内容
主机 .16 .17 .18 .19 .20 .28 共 6 台
文件 新增 /etc/lmod/site/SitePackage.lua;改 /etc/profile.d/zzz_site_lmod.sh、.csh(各追加 LMOD_PACKAGE_PATH 段);内容主节点新增 /opt/modulefiles/siemens/calibre/.modulerc.lua;删除 /opt/modulefiles/Core/slurm/
是否停服 否,不重启 daemon
在跑作业 不受影响(只改登录环境变量与模块可见性)
窗口期 随时;删目录前有备份,可回滚

5. 分步操作

本次以生成器代码为准(改 slurm_ins 的渲染与部署逻辑),下发由部署器完成。以下给出等价底层操作供阅读、复核与手工复现;幂等与错误处理由实现体保证。 实现体:module_env_assets.py(渲染)、module_env_deployer.py(判定/执行/验证/卸载)。

步骤 1:渲染站点 Lmod 扩展 SitePackage.lua

Lmod 的 initialize_lmod()(libexec/utils.lua)先 require("StandardPackage"),再把 LMOD_PACKAGE_PATH 的每个目录前置进 package.path,最后 require("SitePackage");而 Hook.register 的默认动作是 replace——故站点文件里注册的 msgHook 会覆盖默认实现,这是 Lmod 官方留的扩展点(rpm 自带的 SitePackage.lua 只是占位文件)。

坑:SitePackage.lua 一旦出错会让全站 Lmod 失效,故只覆盖 msgHook、其余消息沿用与 StandardPackage 同构的默认格式化(string_utils 的 split/fillWords + TermWidth),并在下发前用实机 luac -p 与隔离 LMOD_PACKAGE_PATH 功能验证。

# 备份(若已存在)
cp -a /etc/lmod/site/SitePackage.lua /etc/lmod/site/SitePackage.lua.bak.$(date +%Y%m%d-%H%M%S)
mkdir -p /etc/lmod/site
cat > /etc/lmod/site/SitePackage.lua <<'EOF'
-- 站点 Lmod 扩展(由 slurm 部署器生成,请勿手工修改)
require("strict")
require("TermWidth")
require("string_utils")
local hook = require("Hook")
local i18n = require("i18n")

local function default_msg(kind, a)          -- 与 StandardPackage 默认 l_msg 同构
   local twidth = TermWidth()
   local s = i18n(kind, {}) or ""
   if (s:len() > 0) then
      for line in s:split("\n") do
         a[#a+1] = "\n"
         a[#a+1] = line:fillWords("", twidth)
      end
      a[#a+1] = "\n"
   end
   a[#a+1] = "\n"
   return a
end

local silent = { ["avail"] = true }          -- 屏蔽的消息类型

local function site_msg(kind, a)
   if (silent[kind]) then return a end
   return default_msg(kind, a)
end

hook.register("msgHook", site_msg)
EOF
chmod 644 /etc/lmod/site/SitePackage.lua
luac -p /etc/lmod/site/SitePackage.lua       # 语法自检,必须无输出

预期:luac -p 无输出;module --config | grep -i 'Site Pkg location' 显示 /etc/lmod/site/SitePackage.lua(未生效时显示 standard)。

步骤 2:把 LMOD_PACKAGE_PATH 写进双轨站点脚本

必须 export/setenv——Lmod 每次启动都从环境读该变量。csh 侧 case 模式串须为字面路径(csh 不对模式做变量展开),判重避免重复 source 时叠加。

# /etc/profile.d/zzz_site_lmod.sh 追加(高危:覆盖前先备份)
_lmod_pkg_dir="/etc/lmod/site"
case ":${LMOD_PACKAGE_PATH:-}:" in
  *":${_lmod_pkg_dir}:"*) ;;
  *) LMOD_PACKAGE_PATH="${_lmod_pkg_dir}${LMOD_PACKAGE_PATH:+:$LMOD_PACKAGE_PATH}"
     export LMOD_PACKAGE_PATH ;;
esac
unset _lmod_pkg_dir

# /etc/profile.d/zzz_site_lmod.csh 追加
if ( ! $?LMOD_PACKAGE_PATH ) then
    setenv LMOD_PACKAGE_PATH "/etc/lmod/site"
else
    switch (":${LMOD_PACKAGE_PATH}:")
    case "*:/etc/lmod/site:*":
        breaksw
    default:
        setenv LMOD_PACKAGE_PATH "/etc/lmod/site:${LMOD_PACKAGE_PATH}"
        breaksw
    endsw
endif

预期:bash -n 无输出;/bin/csh -f -c 'source /etc/profile.d/zzz_site_lmod.csh; printenv LMOD_PACKAGE_PATH' 输出 /etc/lmod/site。

步骤 3:生成器取消 slurm 模块并登记退役目录

module_env.slurm_module.enabled=false 后 modulefile_paths() 不再产出该文件;但生成器只写不删,历史文件会继续被扫到,故由 obsolete_module_file_dirs(本站自有常量,非通配)声明待清理目录 Core/slurm。

# 生成器:slurm_module.enabled: false  →  不再渲染 Core/slurm/<ver>.lua
# 部署器:sync 探测 [ -d /opt/modulefiles/Core/slurm ] → apply 备份后删除

预期:module avail 的 Core 段不再出现 slurm/26.05.2。

步骤 4:内容主节点备份并清理退役目录

高危:删除共享盘模块目录影响全体用户,故先打包备份、备份失败即中止(实现体用 && 串联)。

# 在内容主节点 192.168.31.16 上
B=/var/backups/slurm/modulefiles; mkdir -p "$B"
tar -C /opt/modulefiles -czf "$B/Core-slurm.removed.tar.gz" Core/slurm
rm -rf /opt/modulefiles/Core/slurm
test ! -e /opt/modulefiles/Core/slurm && echo PRUNED

步骤 5:同工具多版本默认值与别名(.modulerc.lua)

yaml 工具条目加 default_version: true 与 version_aliases: ["latest"],渲染成 siemens/calibre/.modulerc.lua:

cat > /opt/modulefiles/siemens/calibre/.modulerc.lua <<'EOF'
module_version("calibre/2026.1", "default")
module_version("calibre/2026.1", "latest")
EOF

预期:module load siemens 后 module -t avail 出现 calibre/latest(@calibre/2026.1);module load calibre 命中 calibre/2026.1。

步骤 6:下发(实现体入口)

.venv/bin/python main.py --config config/slurm_deploy.yaml --module-env --dry-run   # 预演
.venv/bin/python main.py --config config/slurm_deploy.yaml --module-env             # 下发

预期:待执行变更 > 0、退出码 0、末尾 ✅ 部署完成 且健康校验通过。

6. 验证

# 命令 实测结果
1 6 台 module --config \| grep -i 'Site Pkg location' 均为 /etc/lmod/site/SitePackage.lua ✅
2 su - cy01 -c 'module avail' 2>&1 \| grep -c 'avail list is too long' 0(对照组无 LMOD_PACKAGE_PATH 时为 1,即机制确由站点扩展生效) ✅
3 su - cy01 -c 'module avail' Core 段为 cadence pdk siemens site synopsys,无 slurm ✅
4 .16 上 test ! -e /opt/modulefiles/Core/slurm 已删除;备份包 /var/backups/slurm/modulefiles/Core-slurm.removed.tar.gz(620 B)存在 ✅
5 su - cy01 -c 'module load siemens; module -t avail' calibre/latest(@calibre/2026.1)、calibre/2026.1、calibre/2015.2_36.27 ✅
6 隔离树功能测试(/tmp 造两版本 + 真实生成的 .modulerc.lua) module load calibre rc=0 → 加载 calibre/2026.1 ✅
7 6 台 csh 登录态 MODULEPATH 含 /opt/modulefiles/Core 全部通过(双轨脚本改动未回归) ✅
8 幂等复跑 --module-env 第二次「待执行 0 / 幂等跳过 27 / 退出码 0」 ✅

7. 回滚

系统侧(恢复变更前状态):

# 1) 还原被清理的 modulefile 目录(内容主节点 .16)
tar -C /opt/modulefiles -xzf /var/backups/slurm/modulefiles/Core-slurm.removed.tar.gz
# 2) 移除站点扩展与别名
rm -f /etc/lmod/site/SitePackage.lua /opt/modulefiles/siemens/calibre/.modulerc.lua
# 3) 恢复双轨站点脚本中「无 LMOD_PACKAGE_PATH 段」的旧内容
#    (旧内容 = 从 backup/slurm_ins/ 的源文件重新渲染;实现体入口见下)
.venv/bin/python main.py --config config/slurm_deploy.yaml --module-env --rollback

--rollback 会恢复 slurm.conf 的 TaskProlog、删除站点脚本与 SitePackage.lua,并从备份包还原 Core/slurm(实现体 uninstall() 已含该步)。

代码侧:从 backup/slurm_ins/ 恢复源文件后复跑 --module-env。注意:

  • config/slurm_deploy.yaml.bak.20261005-150000 是本轮动手前状态(由本轮 4 处编辑逆向重建,精确);
  • 两个 .py 的历史备份早于本轮改动(分别是 10-05 主题与 09-27 主题的快照),不是动手前快照——需按本 SOP 第 5 章的改动手工逆向,或直接回退到「不复用旧文件、只撤销第 5 章各步」的方式。

备份位置与清单见 backup/README.md。

8. 风险说明

风险 缓解
SitePackage.lua 出错导致全站 Lmod 不可用 只覆盖 msgHook,其余逻辑与 StandardPackage 同构;下发前 luac -p + 隔离 LMOD_PACKAGE_PATH 功能验证(提示块 1→0);6 台 verify() 每次校验 module --config 的 Site Pkg 位置
删除共享盘 Core/slurm/ 影响用户脚本 已核查:全站家目录仅 cy01/1(module help 输出留档)与 rain01/.history(csh 历史)命中 module load slurm,无任何脚本依赖;删除前打包备份,--rollback 可还原
健康检查失去「load 后命令可见」样本 verify_modules 置空,改由 SitePackage 生效 + Core 路径可见 + csh 站点脚本三项覆盖;Slurm 命令可达性由 node_env / submit_node 两阶段各自验证
.modulerc.lua 与兼容侧维护的 calibre/2015.2_36.27 冲突 该文件只声明默认与别名,不改动任何既有 modulefile;2015.2_36.27 仍可显式加载
流程缺口(已记):本轮动手前未先生成两个 .py 的动手前快照(仅 yaml 做了逆向重建) 变更已验收通过且幂等;代码侧回滚按第 5 章逐处逆向编辑执行;后续同类变更必须先做源文件快照再动手

附录:本次交付物与未落地项

文件 说明
backup/slurm_ins/config/slurm_deploy.yaml.bak.20261005-150000 动手前配置(逆向重建,600)
backup/slurm_ins/module_env_assets.py.bak.20261005-135507 等 历史版本源文件(非动手前快照,见第 7 章说明)
本 SOP.md 变更档案

未在本轮落地(按建议顺序留待后续):

  • ④ Spider cache:实测本机 Lmod 的 Cached loads (LMOD_CACHED_LOADS) 为 no(默认不用缓存),启用需同时生成缓存 + 置 LMOD_CACHED_LOADS=yes + 内容变更后重建,否则会「看不到新模块」。当前模块树仅 ~10 个模块,收益为零而风险非零,建议 EDA 工具树就位前再启用(届时落在 --module-env 的收尾步骤)。
  • ⑤ deprecate() 标注与命名统一:目标对象(synopsys/vcs-el7、synopsys/eda2018、calibre/2015.2_36.27、virtuoso/IC06.17.700 等)不在本工程生成器管辖内(由 eda_tools_ins 兼容侧维护),改名会破坏其归属;建议改为在生成器侧支持 deprecated: true(供纳管工具使用),跨工程改名另立变更。

来源:/home/rain/Documents/slurm/slurm_ins/lmod_site_package_20261005/SOP.md | 最后更新:2026-10-05 14:57(由 build/sync.py 同步,请勿在站点侧修改)