✨ feat(agent): 添加 token 鉴权和流程文档

* 默认监听调整为 0.0.0.0:8080,并要求查询参数 token
* 支持首次 run 自动生成含随机 token 的配置文件
* 补充 HTTP 鉴权、配置校验和相关测试
* 完善代码注释,覆盖缓存、上报、服务和平台采集路径
* 新增架构与开发流程文档,补充一键构建脚本
This commit is contained in:
codex
2026-05-22 06:46:21 +00:00
parent 877e4cf41d
commit de3fd88948
19 changed files with 875 additions and 125 deletions

172
docs/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,172 @@
# MFD Monitor Agent 架构与工作流程
本文档汇总当前代码中的实际运行流程,供开发、排障和评审时快速理解 agent 如何从配置加载到采集、缓存、查询、上报和服务化运行。
## 进程职责
MFD Monitor Agent 采用单进程一体化架构。一个 agent 进程同时负责:
- 周期采集主机状态
- 保存最近一次 `HostStatus` 内存缓存
- 提供本地 HTTP API
- 可选地向中心端主动 POST 上报
- 执行 Linux/Windows 服务安装、启动、停止和卸载命令
HTTP 查询与主动上报读取同一份缓存,不在请求路径上触发实时系统扫描。
## 包职责
| 包 | 职责 |
|----|------|
| `cmd/agent` | CLI 分发、配置加载、进程生命周期、HTTP server 启停 |
| `internal/config` | 默认配置、JSON 读取、首次配置生成、环境变量覆盖、配置校验 |
| `internal/status` | `/status` 与主动上报共用的 `HostStatus` JSON 数据模型 |
| `internal/collector` | 平台相关主机、网络、资源、进程、TCP 监听采集 |
| `internal/snapshot` | 子采集器聚合、partial 错误记录、并发安全缓存 |
| `internal/httpapi` | `GET /health` 与 `GET /status`,查询参数 token 鉴权 |
| `internal/reporter` | 周期性 POST 缓存快照,失败重试与日志记录 |
| `internal/service` | Linux systemd 与 Windows SCM 服务生命周期封装 |
## 启动与生命周期
`agent` 无参数时等价于 `agent run`。
`agent run [-config config.json]` 流程:
1. 解析 `-config`,未指定时使用当前工作目录 `config.json`。
2. 调用 `config.LoadOrCreate`。配置不存在时创建默认 JSON 并生成随机 `http.token`。
3. 创建 `snapshot.Cache`,启动后台采集循环。
4. 若 `report.enabled=true`,启动主动上报循环。
5. 启动 HTTP server,默认监听 `0.0.0.0:8080`。
6. 收到 `SIGINT` 或 `SIGTERM` 后优雅关闭 HTTP server。
服务命令 `install`、`uninstall`、`start`、`stop` 使用 `config.Load` 读取已有配置,不会自动创建配置文件。
## 配置加载流程
配置来源按以下顺序生效:
1. `config.Default()` 提供默认值。
2. JSON 文件覆盖默认值。
3. `MFD_AGENT_*` 环境变量覆盖 JSON。
4. `validate` 校验安全和必填项。
关键规则:
- `http.token` 必填;`agent run` 首次生成配置时会自动写入随机 token。
- `report.enabled=true` 时 `report.endpoint` 必填。
- 自动生成的配置文件权限为 `0600`,因为其中包含 API token。
- 非法布尔或时长环境变量会被忽略,保留文件中的原值。
## 采集与缓存流程
`snapshot.Cache.Run` 启动后立即采集一次,随后按 `collect.interval` 周期刷新。
每轮采集流程:
1. 用 `collect.timeout` 创建整体超时 context。
2. 构造新的 `HostStatus`,默认 `agent.snapshot_status=ok`。
3. 依次执行 `system`、`network`、`resource`、`process`、`socket` 采集器。
4. 子采集器失败时记录到 `errors[]`,整份快照降级为 `partial`,其他字段继续保留。
5. 用锁一次性发布最新快照,供 HTTP 与 reporter 并发读取。
`processes.status` 与 `tcp_listeners.status` 支持 `ok`、`partial`、`error`。例如 Linux 读取 `/proc/<pid>/fd` 权限不足时,TCP 端口仍会返回,但进程映射可能不完整并标记为 `partial`。
## HTTP 查询流程
所有 API 都要求查询参数 token:
```text
GET /health?token=<http.token>
GET /status?token=<http.token>
```
处理流程:
1. `withQueryTokenAuth` 使用恒定时间比较校验 token。
2. token 缺失、错误或配置 token 为空时返回 `401`。
3. 非 `GET` 方法返回 `405`。
4. `/health` 读取缓存元数据。首次快照未就绪时返回 `503` 和 `{"status":"starting"}`。
5. `/status` 返回完整缓存 `HostStatus`。首次快照未就绪时返回 `503`。
HTTP 请求不会触发采集,避免高并发查询放大系统扫描成本。
## 主动上报流程
启用条件:
```json
{
"report": {
"enabled": true,
"endpoint": "http://center.example.internal/agent/status"
}
}
```
运行流程:
1. `reporter.Run` 按 `report.interval` 定时执行。
2. 从 `snapshot.Cache` 读取最新 `HostStatus`。
3. 首次快照未就绪时跳过本轮。
4. 以 `application/json` POST 到 `report.endpoint`。
5. 非 2xx、网络错误或超时视为失败。
6. 失败后等待短暂退避并重试一次。
7. 最终失败只记录日志,不影响采集循环或本地 HTTP 服务。
上报载荷与 `/status` 响应结构完全一致。
## 服务生命周期流程
### Linux systemd
`agent install -config /path/config.json -exe /path/agent`:
1. 检查当前用户必须为 root。
2. 生成 `/etc/systemd/system/<service.name>.service`。
3. `ExecStart` 写入 `<exe> run -config <path>`。
4. 执行 `systemctl daemon-reload`。
5. 执行 `systemctl enable <service.name>`。
`start`、`stop` 调用 `systemctl start/stop`。`uninstall` 尽力 `disable --now`,删除 unit 文件后再次 `daemon-reload`。
### Windows SCM
Windows 通过 `sc.exe` 管理服务,不依赖 NSSM。
`install` 使用 `sc.exe create` 注册自动启动服务,`binPath` 为:
```text
"<exe>" run -config "<config>"
```
`start`、`stop`、`uninstall` 分别调用 `sc.exe start`、`sc.exe stop`、`sc.exe delete`。安装、删除和启停通常需要管理员权限。
## HostStatus 数据模型
`HostStatus` 是唯一对外状态模型,同时用于:
- `GET /status` 响应体
- 主动上报 POST body
- 测试中的快照断言
顶层字段包括:
- `agent`:版本、启动时间、快照时间、快照状态
- `host`:机器标识、主机名、平台、架构、运行时长
- `network`:网卡明细、IPv4/IPv6、MAC
- `cpu`:逻辑核心、物理核心、使用率、负载、型号
- `memory`:内存容量与使用率
- `disks`:文件系统容量与使用率
- `processes`:采集状态与完整进程列表
- `tcp_listeners`:采集状态与 TCP 监听端口到进程映射
- `errors`:子采集器失败原因
## 平台差异
Linux 采集主要读取 `/proc`、`/etc/os-release`、`net.Interfaces` 和 `statfs`。进程与 socket 映射受 `/proc/<pid>` 权限和进程生命周期竞争影响。
Windows 采集使用 Win32 API、Toolhelp、注册表、PSAPI、iphlpapi 和一次尽力 WMIC 命令。部分字段需要高权限读取进程句柄或令牌,失败时降级为空字段或 `partial`。
非 Linux/Windows 平台保留基础主机和网络采集,进程与 TCP 监听采集明确返回不支持并标记 `partial`。