diff --git a/admin-plane-gaps.md b/admin-plane-gaps.md index 9d61683b..8bc03f74 100644 --- a/admin-plane-gaps.md +++ b/admin-plane-gaps.md @@ -87,21 +87,47 @@ | 子项 | 判定 | 现状与证据 | |---|---|---| | 概念/定义/配置 | ✓ | resources.yaml 全谱系:内置负载指数、host 属性(type/model/cpuf/maxmem/…)、static(shared/hostbased)、dynamic、boolean/string、resourcemap;JSON Schema 校验;join 时按 hostconfig 播种(mark_host_res/add_hostattrs_resvals/set_host_slots,worker.c:232-341)。 | -| resource 种类 | △ | valtype STRING/NUMERIC/BOOLEAN、ordtype INCR/DECR/NA、9 个 flags 齐备(types.h:81-89)。**关键接线断裂:YAML→capnp 映射只映射 CONSUMABLE 和 RELEASE 两个 flag**(mapping.py:194-200)——DYNAMIC/SHARED/GLOBAL/EXTERNAL/BUILTIN 从 YAML 永远置不上;resourcemap 在 build 时被静默丢弃(build.py:38-65 _UNMAPPED_BUT_VALID_ITEM_KEYS,capnp:192-206 目标字段被注释)。ordtype 存了但**无消费者**(排序纯 first-fit,关联 t1 亲和)。 | -| load index | ✓ | **11 个内置指数全部真采集**:r15s/r1m/r15m/ut/pg/ls/it/swp/mem/tmp/io,~15s 周期(resource_sync.c:60-106),实现实在(node_information.c:/proc/loadavg、utmp、MemAvailable、statvfs、diskstats…),推送链完整(resvals→controller opupd.c→RESVALS_DELTA→scheduler core_events.c:1228-1263)。实测 distribution list 有 io/it/ls/mem 值。 | -| static resource | △ | 声明与播种 ✓(hostbased 静态值随 join 落地);但 share 型静态资源的 resourcemap(实例/份额定义)在 build 时被丢(见上),**静态 share 资源实际不工作**。 | +| resource 种类 | △→✓ | valtype STRING/NUMERIC/BOOLEAN、ordtype INCR/DECR/NA、9 个 flags 齐备(types.h:81-89)。~~YAML→capnp 映射只映射 CONSUMABLE 和 RELEASE~~ **断点 ② 已修(2026-10-23)+ BUILTIN 键补链(857f987f)+ EXTERNAL 键(E2,mapping.py:448)**:现 YAML 可置 CONSUMABLE/RELEASE/BUILTIN/SHARED|GLOBAL(location:[all]+value)/SHARED|GLOBAL|EXTERNAL(location:[external])五个语义组;resourcemap→distributions 上 wire(schema distributions/hostBased 取消注释 + 深拷)。仍缺:DYNAMIC flag 无独立 YAML 键(dynamic 形态靠 interval+无 resourcemap 隐式表达)、ordtype 仍无消费者(排序纯 first-fit)。 | +| load index | ✓ | **11 个内置指数全部真采集**:r15s/r1m/r15m/ut/pg/ls/it/swp/mem/tmp/io,~15s 周期(resource_sync.c:60-106),实现实在(node_information.c:/proc/loadavg、utmp、MemAvailable、statvfs、diskstats…),推送链完整(resvals→controller opupd.c→RESVALS_DELTA→scheduler core_events.c:1228-1263)。实测 distribution list 有 io/it/ls/mem 值。**E2 增补(2026-10-28):外部 elim 脚本源可注册进同一条链**(elim.c:595 resource_sync_register_load_index),主机级外部资源与内置指数同一推送通路。 | +| static resource | △→部分✓ | 声明与播种 ✓(hostbased 静态值随 join 落地);~~share 型静态资源的 resourcemap 在 build 时被丢~~ **断点 ② 已修**:`location: [all]`+value 形态置 SHARED\|GLOBAL 并 seed 进 sharedinst(幂等激活热更新容量);**host 子集静态共享池**(dynres2 的多 host 份额形态)仍不工作——distributions 忠实上 wire 但调度器只认 [all] 形态(elastic-shared-resources 仍规划)。 | --- ## 1.7 外部 resource(external resource) -**✗ 缺失。** +> **2026-10-29 复评:✗ → △→✓(license 全局池 + elim 主机级采集两条腿已落地,E2 三阶段完成)。** +> 实现 = `.kiro/specs/external-license-resources/`(design.md §3.5 分阶段),随 merge 9b652d93 进 working。 +> 本节原"✗ 缺失"清单的逐项消解见下《E2/elim 完成面对照》。 -- XCE_RESF_EXTERNAL(0x10) 定义了但全库无 setter。 -- 无 elim 式外挂采集器:worker 没有子进程/脚本采集路径;`resource_sync_register_load_index` 是进程内 C API(给 xcecd 内部代码用),无任何调用方。 -- dynres1/dynres2 声明了 interval 但**无采集者**——定义在表里、值永远不会自动出现,只能管理员手工 update_resval 推。 -- scaler.yaml(aws-asg/k8s-pool)映射为 hproviders 推给 scheduler,但 **scheduler 零消费者**(而且它是自动扩缩 provider,不是资源采集器)。 -- .kiro/specs/custom-resource-reporting 已规划未实施。 +**已具备(E2 Phase 1/2/3 + elim,2026-10-27/28/29)**: + +- **EXTERNAL flag 全链**:XCE_RESF_EXTERNAL 有声明式 setter(mapping.py `location: [external]` → SHARED|GLOBAL|EXTERNAL 0x1C,mapping.py:448-452);调度准入 EXTERNAL 判式落地(resource.c:176/198 unsatisfy_ `is_external` 两分支:EXTERNAL `total ≥ uncomit + wanted`,跳过 inuse 项——free 值语义,对齐 Slurm GRES/LSLicense 路线而非 LSF bld 归因路线)。 +- **独立采集 daemon xceesd**(src/esd/,XCE_TESTING 之外首条 daemon 形采集链):script 采集器(esd_script.c,外部命令 stdout JSON)+ flexlm 接口位(esd.h:22,同一 interface 覆盖 `lmstat -a`);esd.yaml 配置(cyaml schema);join/rejoin/透明重连即全量重推(bug-1978 修复 b471ce31);fail-open 断联策略(esd.c:100-109,保旧值 + stale WARN 升级,`stale_limit` 默认 150s)。 +- **wire 零 schema 变更**(复用 RESVALS_DELTA + HostRole `extres`);opupd 守卫"SHARED 即收"(为 elastic-shared 留同一通道)。 +- **运维面(Phase 2)**:stale 逐源标记 + WARN 全链;`xceadmin extres status`(本地 status file JSON 渲染,value/age/STALE);resources dump 渲染 `external=True`/`builtin=True`/distributions(build.py:221-227)。 +- **策略层(Phase 3)**:per-project/per-queue license 配额 = limit vres 机制复用(ServiceDomain≈queue、DISTRIBUTION≈limit 配额的 LSF 词汇映射);根因修复 bug-1976(controller dispatch 重建丢 allocs_shared → vres 永不计费、global limit 全失效);t1 E2E 三 projA RUN/第 4 PEND/kill 再准入实证。 +- **elim 主机级采集(design §3.3b,归 xcecd 不归 esd)**:worker/src/elim.c(656 行)——xcecd.yaml `external_resources:` 脚本源声明 → 子进程采集 → `resource_sync_register_load_index` 接入既有 11 内置指数同一条推送链(elim.c:595);EXTERNAL 记账规则同一套(全局 license 与主机 elim 两条腿同一模型)。 + +**仍缺(按 design 未做项 + 新边界)**: + +- dynres1/dynres2 类**通用 dynamic 资源仍无通用采集钩子**——elim 采集器只覆盖"显式声明 external_resources 的脚本源";任意外部程序报告任意资源名的 LSF elim 全等价物(custom-resource-reporting spec)仍属规划。当前答案是"再写一个 elim 源",不是"自动发现"。 +- **multi-daemon 冗余**(Phase 3 原计划项:多 xceesd last-writer-wins)未实现——单 daemon 部署是唯一验证过的形态。 +- **手动覆盖 REST**(管理员临时改 free 值)按 design 有意不做。 +- **esd 状态只在本机**:`xceadmin extres status` 读 daemon 本地 status file,无远程通道(design 3.6 有意留给 PR-2 proxy,未建 proxy)。 +- **merge 归因报告层**(design §3.3c Tier 0-3 + 残差桶闭合):准入免疫已达成(判式只用聚合值),但 Tier1'/Tier2 匹配器、对账 alert 均未实现——多 app 共享同一 license 时账目只能给"我们放行了什么"(limit vres 记账),给不出"他们持有什么"的分解。 +- P9 共享池写入权按资源分模式(EXTERNAL=server 赢/无 flag=elastic provisioner 赢)已按此实现,但与 Rongsong 的 §3.6 合并确认仍未做(提请决策项 2/3 未决)。 + +**原 ✗ 清单其余项不变**:scaler.yaml→hproviders 依旧 scheduler 零消费者(身份是 provider 非采集器,另案);.kiro/specs/custom-resource-reporting 仍规划未实施。 + +### E2/elim 完成面对照(gaps 原文 → 现状) + +| 原 gaps 记载 | 现状 | +|---|---| +| XCE_RESF_EXTERNAL 全库无 setter | ✓ 已接:mapping.py:448 `location: [external]` | +| 无 elim 式外挂采集器 | ✓ 已接:elim.c 脚本采集 + xceesd 全局采集(两条腿) | +| `resource_sync_register_load_index` 无调用方 | ✓ 已接:elim.c:595 | +| dynres 声明 interval 无采集者 | ✗ 仍缺(同上,通用钩子未做) | +| .kiro/specs/custom-resource-reporting 未实施 | ✗ 仍规划(elim 覆盖其"脚本源"形态,非全部) | --- @@ -129,11 +155,12 @@ ## 1.10 shared resource -**△ 机制存在,端到端不通。** +> **2026-10-29 复评:机制存在端到端不通 → 集群级([all]+value / [external])形态端到端已通,host 子集形态仍缺。** -- 机制 ✓:SHARED flag 资源进集群级共享池 c->sharedinst(worker.c:65-143 按 flag 路由);调度两段式——先集群级 precheck(sched_alloc_prepare_shared_,alloc_runner.c:73-132,不满足→无主机 PEND 行+PREASON_NO_RESOURCE/LIMIT_GLOBAL)再逐主机检查;snapshot 以 host==NULL 池形态携带恢复(bug-1923)。limit vres(GLOBAL limit)是当前唯一活的生产者。 -- 断点 ✗:YAML 映射不置 SHARED flag(mapping.py:194-200)+ resourcemap(LSF 式静态份额/实例定义,如 dynres2 host1:50/host2:50)build 时丢弃 → **静态共享资源(license 类场景)声明得、用不上**;实测 distribution list 只有 hostbased 行,无共享实例行。 -- .kiro/specs/elastic-shared-resources、resource-instances 已规划未实施。 +- 机制 ✓:SHARED flag 资源进集群级共享池 c->sharedinst(worker.c:65-143 按 flag 路由);调度两段式——先集群级 precheck(sched_alloc_prepare_shared_,alloc_runner.c:73-132,不满足→无主机 PEND 行+PREASON_NO_RESOURCE/LIMIT_GLOBAL)再逐主机检查;snapshot 以 host==NULL 池形态携带恢复(bug-1923)。 +- ~~断点 ✗:YAML 不置 SHARED flag + resourcemap build 时丢弃~~ **断点 ② 已修(2026-10-23,见文末)**:`location: [all]`+value 静态共享池(license 类场景的最简形态)声明即用,seed 进 sharedinst 且激活热更新。 +- **E2 补全(2026-10-27/28)**:动态侧两个活的生产者——① xceesd 对 `location: [external]` 资源推 free 值(同一 sharedinst 通道,EXTERNAL 判式免 inuse 双扣);② limit vres(GLOBAL limit,Phase 3 扩展到 per-project/per-queue license 配额,bug-1976 修复使记账真正生效)。共享池 PEND reason 带资源名(alloc_runner.c:114 LIMIT_GLOBAL/NO_RESOURCE 判定)。 +- **仍缺**:host 子集静态共享池(dynres2 host1:50/host2:50 形态——distributions 上 wire 但调度器零消费者,需 per-host 实例分账,elastic-shared-resources spec 仍规划);sharedinst 手动 update_resval 运维通道未验证;resource-instances spec 仍规划。 --- @@ -144,7 +171,7 @@ | N1 | `xce id` 空壳:集群名/状态/管理员全空 | 实测输出 `<>`;handler.go:225 注释 | | N2 | `queues list` 显示与准入不一致:closed 队列显示 open:active | 实测(close night 后提交被拒、list 仍 open:active) | | N3 | exit code 不上 job API(REST ExitStatus 死字段) | convert_pure.go:646 无映射;SSE 有 exit_code | -| N4 | done 作业 live 无 GC、无 purge API、无归档:长运行 controller 终态作业内存只增不减 | persist.c:2558 唯一执行点;kvmgr.c:279 del_key=NULL;实测积压一天+ | +| N4 | done 作业 live 无 GC、无 purge API、无归档:长运行 controller 终态作业内存只增不减 | persist.c:2558 唯一执行点;kvmgr.c:279 del_key=NULL;实测积压一天+。**→ 断点 ③ 已修 live GC(2026-10-23,见文末),purge API/归档仍缺** | | N5 | `jobs peek` 对已结束作业 501 | 实测 GET /jobs/:id/output status 501 | | N6 | `jobs submit --configfile` 不解析配置行,拼进命令行当作业命令执行 | 实测:job.xce 两行变成 command "queue=short job_name=cfgtest2" | | N7 | 用户无 CRUD:无 add/delete user、无改密码端点,加人=改 auth.yaml+重启 | routers.go 全量;users 命令族仅角色指派 | @@ -161,14 +188,15 @@ - gaps.md 一~七节(调度/架构/构建)全部继续有效,本文不重复;交叉引用已标注(#3 fairshare、#4 sched_delay、#6/#7/#15 PEND reason、#9 心跳窗、#12 配置传播、#17 执行上下文)。 - .kiro/specs 的空目录(elastic-hosts、controller-job-cleanup、job-dependency、gang-groups、resource-instances、custom-resource-reporting、host-failure-job-recovery、elastic-shared-resources、rbac-persistence、project-* 等)正是本评估所列缺口的"已规划未实施"标记;xce-node-manager 有完整 spec。规划面与管理面缺口高度吻合,说明缺口识别一致,缺的是实施。 +- **2026-10-29 更新**:`external-license-resources` 是其中**已实施完成**的一个 spec(E2 Phase 1/2/3 + elim,见 1.7 复评);1.7/1.10/1.6 的相关缺口随之消解(详见 1.7 的对照表)。 ## 四、若按用户价值排优先级(供第二步讨论) 1. **配置可达性**:让 config push 真正到达 live scheduler(gaps #12 的一半收益)+ 既有队列编辑热生效——"配了不生效"是管理面最大的信用问题。**→ 已作为断点 ① 修复,见下。** 2. **可见性补齐**(低风险高价值):queues list 状态显示修复(N2)、exit code 上 API(N3)、cluster info 填实(N1)、user/host group 查询端点(N9)、daemon/HA 状态只读命令(ctrlstatus 已有协议只差暴露)。 -3. **生命周期补齐**:done 作业 GC+purge 命令(N4)、host 删除流程(elastic-hosts spec 落地)、用户 CRUD(N7)。 +3. **生命周期补齐**:done 作业 GC+purge 命令(N4,**GC 部分已作为断点 ③ 修复**,purge/归档仍缺)、host 删除流程(elastic-hosts spec 落地)、用户 CRUD(N7)。 4. **管理动作补齐**:requeue/mig 控制动作(枚举已在、REST 400 挡着)、host 故障作业恢复策略(host-failure-job-recovery spec)。 -5. **资源接线**:shared/external resource 的 YAML→capnp 断点(mapping + resourcemap 注释字段)、dynres 采集钩子(custom-resource-reporting spec)。 +5. **资源接线**:shared/external resource 的 YAML→capnp 断点(mapping + resourcemap 注释字段)、dynres 采集钩子(custom-resource-reporting spec)。**→ 已大部分完成:断点 ②(SHARED/resourcemap 接线)+ E2(EXTERNAL 全链 + elim 采集 + per-project/queue 策略层,见 1.7);余项 = 通用 dynres 采集钩子、host 子集静态共享池(elastic-shared-resources)。** ---