4.6 KiB
控制平面 ↔ Host Agent 协议
当前状态(2026-07-27):独立 Host Agent 已实现注册、注册口令、bearer token、 本地
0600凭据文件、主机指纹和心跳;控制平面只保存 token SHA-256 摘要。 心跳迟到 15 秒会把 Host 降级为DEGRADED,丢失 30 秒会标记为OFFLINE; 安全预检会先刷新该状态,避免失联 Host 被误判为可用。 Step 租约、事件、完成与产物端点仍是下一阶段契约。make demo暂时继续使用 控制平面内置模拟执行器验证状态、恢复与证据链。
Agent 是拉模式。控制平面永远不主动连接测试主机。
理由:客户测试主机在内网/NAT 后面,很多实验室根本不给外部反连; 拉模式还顺带解决了 Agent 重启后的重新接入问题。
端点
| 状态 | 方法 | 路径 | 用途 |
|---|---|---|---|
| 已实现 | POST | /api/v1/agent/register |
首次注册 / token 轮换;上报主机指纹与工具能力 |
| 已实现 | POST | /api/v1/agent/{agent_id}/heartbeat |
bearer 心跳,上报健康和设备探针;返回待办指令 |
| 已实现 | GET | /api/v1/agent/hosts |
查看 Host 与 Agent 在线投影,不返回 token |
| 待实现 | POST | /api/v1/agent/{agent_id}/lease |
领取下一个步骤(长轮询,最多挂 20s) |
| 待实现 | POST | /api/v1/agent/{agent_id}/steps/{step_id}/events |
批量上报执行事件与日志片段 |
| 待实现 | POST | /api/v1/agent/{agent_id}/steps/{step_id}/complete |
上报步骤终态 + UnifiedResult + 产物清单 |
| 待实现 | POST | /api/v1/agent/{agent_id}/artifacts |
上传产物(日志 / 结果文件 / 画面) |
带外控制器走独立端点(它必须能在主机死后独立上报):
| 方法 | 路径 | 用途 |
|---|---|---|
| POST | /api/v1/oob/{controller_id}/heartbeat |
带外心跳 + 电源状态 + 温度 + 画面指纹 |
| POST | /api/v1/oob/{controller_id}/observation |
主动上报观测(蓝屏画面、掉电、按钮触发) |
心跳返回的指令
心跳响应已经带 commands 字段;当前固定为空数组。命令队列接入后,Agent 收到后立即执行:
{
"ok": true,
"server_time": "2026-07-27T03:14:15Z",
"commands": [
{"kind": "CANCEL_STEP", "step_id": "..."},
{"kind": "SOFT_RESTART", "reason": "recovery_L1"},
{"kind": "EMERGENCY_STOP", "run_id": "..."},
{"kind": "REFRESH_ASSETS"}
]
}
紧急停止走心跳而不是新连接——心跳是唯一能保证到达的通道。 最坏情况延迟 = 心跳间隔(5s)。真正需要毫秒级的停止靠带外物理急停,不靠软件。
租约(lease)语义
Agent ──lease──▶ 控制平面
├─ 有活:分配步骤,step → DISPATCHED,写租约(TTL 60s)
└─ 没活:长轮询挂起最多 20s,返回 204
Agent ──ack───▶ step → RUNNING
(租约到期未 ack 或未 complete)→ step 回 PENDING,重新派发
租约 TTL 必须大于步骤超时?不——恰恰相反:租约由 Agent 在执行期间通过心跳续期。 Agent 死了 → 心跳停 → 租约到期 → 步骤回收。这是 Agent 崩溃能被发现的机制之一 (另一条是心跳超时判定,见 state-machine.md §5)。
认证
首次注册带 X-FlashOps-Enrollment-Token。开发态未配置注册口令时允许本机演示;
生产态未配置时注册接口返回 503。注册成功下发 bearer token,之后每个请求带
Authorization: Bearer <token>。agent_id 与 test_host_id 绑定,重新注册会轮换 token。
原始 token 仅存于 Agent 本机 0600 state 文件;控制平面数据库只保存 SHA-256 摘要。
Agent 客户端保留可选 gateway Basic Auth 能力,供未来重新启用边界认证或部署在其他网关后使用;
当前 flashops.imagebrewing.com 预览环境未启用这层认证。
下一波必须升级:方案 §6.2 要求"每个 Agent 使用唯一证书或密钥"。
bearer token 在客户内网够用,但要进客户安全评审得上 mTLS。
升级点在 api/deps.py::require_agent() 一处。
幂等(待实现)
Step 租约接入时,所有 Agent → 控制平面的 Step 写请求必须带
Idempotency-Key(Agent 生成的 UUID)。控制平面需要记录并拒绝重复副作用;
run_events 已有唯一约束 (run_id, idempotency_key),但当前注册 / 心跳链路尚未实现
通用的请求幂等存储。
这一条在真实实验室里不是可选项:主机重启、网线松动、Wi-Fi 掉线是常态, 没有幂等就会出现"一次故障记了三条"的时间线,取证时说不清。