Files
Your Name 6726524c50 fix: db.get_or_404 -> query.get_or_404 + rename to Palladium Monitor
- 修复删除快照时 AttributeError: SQLAlchemy.get_or_404 (低版本兼容)
- UI/标题/邮件主题从 'Palladium Z1 Monitor' 改为 'Palladium Monitor'
2026-07-08 14:46:18 +08:00

288 lines
11 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Palladium Monitor
LD 逻辑板使用监控系统 — 解析 `test_server -short` 输出,可视化展示 Palladium 仿真器的逻辑板状态、逻辑板利用率、作业信息和 T-Pod 可用性。
## 功能
- **逻辑板状态可视化** — Rack / Cluster / Board 三级结构,每块 LD 板的 8 个逻辑板 (D0-D7) 以色块展示
- 🟢 可用 (`-`)
- 🔵 已加载/预留 (`<num>`)
- 🔴 已禁用 (`D`)
- ⬜ 不存在 (`X`)
- **实时指标** — 逻辑板总数、在线/离线、逻辑板利用率、活跃作业数
- **作业信息** — 用户、PID、T-Pod、设计名、已运行时间
- **T-Pod 可用性** — 按 Rack 展示 HDSB / T-Pod 的可用/锁定/预留/不可用状态
- **历史趋势** — 利用率折线图 (Chart.js),支持历史快照查看和清理
- **自动刷新** — 可选 15s/30s/1m/5m 间隔自动刷新仪表板
- **多数据来源** — 手动粘贴、API 推送、远程采集脚本
## 快速开始
```bash
cd palladium-monitor
pip install -r requirements.txt --break-system-packages
python3 app.py
```
浏览器访问 `http://localhost:5100`
## 数据采集方式
### 方式一:手动粘贴 (Web 界面)
1. 在 Palladium 主机执行 `test_server -short`
2. 复制完整输出
3. 在 Web 界面点击「📥 粘贴数据」按钮
4. 粘贴输出到文本框,点击「解析并存储」
### 方式二:API 推送 (collect.py + 一键安装)
在 Palladium 主机上部署采集 agent,**推荐**用一键脚本(处理 env 加载、crontab、依赖):
```bash
# 把 palladium-monitor/ 整个目录 scp 到 Z1 主机, 然后:
sudo ./install_z1_agent.sh \
--url http://<监控服务器IP>:5100/api/collect \
--host scmp03 \
--env /edatools/vxe/VXE23.03.001/bin/env.csh \
--interval 30
```
脚本会:建 `/opt/palladium-monitor/`、装 `requests`、备份原 crontab、写入 `*/30 * * * *` 任务、跑一次 dry-run 验证。
**手动部署**(不跑安装器):
```bash
# 安装 requests
pip install requests
# 手动推送一次
python3 collect.py --url http://<监控服务器IP>:5100/api/collect --host scmp03
# 配合 crontab 定时推送 (每30分钟)
*/30 * * * * /opt/palladium-monitor/collect.py --url http://<监控服务器IP>:5100/api/collect --host scmp03 --env /edatools/vxe/VXE23.03.001/bin/env.csh --log /var/log/palladium-collect.log >> /var/log/palladium-collect.cron.log 2>&1
```
#### collect.py 参数
| 参数 | 默认值 | 说明 |
|------|--------|------|
| `--url` | `http://127.0.0.1:5000/api/collect` | 监控服务器 API 地址 |
| `--cmd` | `test_server -short` | 采集命令 |
| `--host` | `hostname` | 本机标签,会写入 `source` 字段 (如 `collect.py@scmp03`) |
| `--env` | — | VXE env.csh/env.sh 路径,脚本自动 `source` 后再执行采集命令 |
| `--timeout` | `300` | 采集命令超时秒数 |
| `--retries` | `3` | 推送失败重试次数 |
| `--retry-delay` | `5` | 重试间隔秒数 |
| `--log` | — | 追加写日志文件路径 |
| `--dry-run` | — | 只采集不推送,打印输出 |
#### 退出码
| Code | 含义 |
|------|------|
| 0 | 成功 |
| 1 | 采集命令无输出 / 失败 |
| 2 | 推送失败 (已重试) |
| 130 | 用户中断 (Ctrl-C) |
cron 收到非 0 时会通过 `MAILTO` 触发告警。
### 方式三:直接 API 调用
```bash
curl -X POST http://<服务器>:5100/api/collect \
-H "Content-Type: application/json" \
-d '{"raw_output": "<test_server -short 完整输出>"}'
```
## API 端点
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/` | 仪表板页面 |
| GET | `/history` | 历史快照列表 |
| GET | `/snapshot/<id>` | 快照详情 |
| POST | `/paste` | 手动粘贴数据 (表单提交) |
| POST | `/api/collect` | 接收原始输出 (JSON) |
| GET | `/api/latest` | 最新快照 JSON |
| GET | `/api/history` | 历史趋势 JSON |
| GET | `/api/export` | 导出历史 (CSV/JSON, 支持时间范围 + 来源过滤) |
| POST | `/api/cleanup?days=N` | 清理 N 天前数据 |
| POST | `/api/snapshot/<id>/delete` | 删除指定快照 |
### 导出历史数据
`/api/export` 端点支持 CSV (Excel 友好, 带 UTF-8 BOM) 和 JSON 两种格式,可按时间范围和来源过滤。
```
GET /api/export?format=csv # 默认: CSV 全部
GET /api/export?format=json # JSON 全部
GET /api/export?days=7 # 最近 7 天
GET /api/export?since=2026-07-01&until=2026-07-31 # 自定义范围
GET /api/export?source=collect.py # 按来源模糊匹配
GET /api/export?format=json&days=30&source=scmp03 # 组合
```
参数说明:
- `format`: `csv` (默认) 或 `json`
- `days`: 限制最近 N 天 (0/缺省 = 全部)
- `since` / `until`: `YYYY-MM-DD` 或 ISO 时间戳
- `source`: 模糊匹配 `source` 字段 (如 `collect.py``scmp03`)
- `limit`: 最多返回条数 (默认 10000, 上限 100000)
CSV 文件名: `palladium_snapshots_YYYYMMDD_HHMMSS.csv`,包含 19 列(时间本地+UTC、仿真器/硬件/ConfigMgr、系统状态、来源、板/域计数、利用率、作业数等)。
Web 界面入口:历史记录页右上角「📤 导出」按钮。
## 解析器支持的输出格式
```
Emulator: sc01_emu Hardware: Palladium Z1 Configmgr: V21.02.102.s002System Status: PARTIAL
Rack 0 has 2 clusters
Cluster 0 has 6 boards CCD: ONLINE
LD Status D0 D1 D2 D3 D4 D5 D6 D7
0 ONLINE - - - - - - - -
...
```
逻辑板状态图例:
- `-` → 可用 (Domain is available)
- `X` → 不存在 (Domain does not exist)
- `D` → 已禁用 (Domain is disabled)
- `<num>` → 已加载/预留 (Domain is downloaded or reserved)
## 项目结构
```
palladium-monitor/
├── app.py # Flask 应用: 解析器 + 数据模型 + 路由 + API
├── collect.py # 远程数据采集推送脚本 (Z1 主机跑)
├── install_z1_agent.sh # Z1 主机一键部署脚本 (env 加载 + crontab + 依赖)
├── requirements.txt # Flask, Flask-SQLAlchemy
├── instance/ # SQLite 数据库
├── templates/
│ ├── base.html # 基础布局 (导航 + 粘贴弹窗)
│ ├── dashboard.html # 主仪表板
│ ├── history.html # 历史记录列表
│ └── snapshot.html # 快照详情页
└── static/
└── style.css # 暗色主题样式
```
## 生产部署
### 监控服务器端
```bash
cd palladium-monitor
pip install -r requirements.txt --break-system-packages
gunicorn --workers 2 --bind 0.0.0.0:5100 app:app
```
### 邮件功能配置 (环境变量)
监控服务启动时会自动读以下环境变量, 无需 Web UI。所有变量都是可选的 (不配就相当于关闭邮件功能)。
| 变量 | 必填 | 默认 | 说明 |
|------|------|------|------|
| `MAIL_ENABLED` | ❌ | `false` | 是否启用邮件功能, 设为 `true`/`1`/`yes` 开启 |
| `SMTP_HOST` | 启用时必填 | — | SMTP 服务器地址 (如 `smtp.gmail.com``smtp.exmail.qq.com`) |
| `SMTP_PORT` | ❌ | `587` | SMTP 端口 (587=STARTTLS, 465=SSL, 25=明文) |
| `SMTP_USER` | 启用时必填 | — | SMTP 登录用户名 (通常等于邮箱地址) |
| `SMTP_PASSWORD` | 启用时必填 | — | SMTP 密码 (Gmail 用 App Password, 16 位) |
| `SMTP_USE_TLS` | ❌ | `true` | 是否用 STARTTLS (端口 587 时设为 `true`) |
| `SMTP_USE_SSL` | ❌ | `false` | 是否用隐式 SSL (端口 465 时设为 `true`) |
| `MAIL_FROM` | 启用时必填 | — | 发件人邮箱 |
| `MAIL_FROM_NAME` | ❌ | `Palladium Monitor` | 发件人显示名 |
| `MAIL_TO` | 启用时必填 | — | 收件人列表, 英文逗号分隔 (如 `alice@x.com,bob@y.com`) |
| `MAIL_SEND_HOUR` | ❌ | `9` | 每天发送时间-小时 (0-23) |
| `MAIL_SEND_MINUTE` | ❌ | `0` | 每天发送时间-分钟 (0-59) |
| `MONITOR_BASE_URL` | ❌ | `http://127.0.0.1:5100` | 监控页 URL (用于邮件里"查看完整仪表板"链接) |
| `ALLOW_EMAIL_TRIGGER` | ❌ | — | 设为 `true` 允许通过 `POST /api/email/send` 手动触发 (默认禁止) |
#### 启动方式
**方式 1: 直接 export**
```bash
export MAIL_ENABLED=true
export SMTP_HOST=smtp.gmail.com
export SMTP_PORT=587
export SMTP_USER=monitor@gmail.com
export SMTP_PASSWORD=**** # Gmail 用 App Password
export MAIL_FROM=monitor@gmail.com
export MAIL_TO=team-lead@company.com,ops@company.com
gunicorn --workers 2 --bind 0.0.0.0:5100 app:app
```
**方式 2: systemd EnvironmentFile (推荐)**
```ini
# /etc/palladium-monitor/mail.env
MAIL_ENABLED=true
SMTP_HOST=smtp.exmail.qq.com
SMTP_PORT=587
SMTP_USER=monitor@company.com
SMTP_PASSWORD=**** # 或从 secret manager 注入
MAIL_FROM=monitor@company.com
MAIL_TO=team@company.com
MAIL_SEND_HOUR=8
MAIL_SEND_MINUTE=30
```
```ini
# /etc/systemd/system/palladium-monitor.service
[Service]
EnvironmentFile=/etc/palladium-monitor/mail.env
ExecStart=/usr/bin/gunicorn --workers 2 --bind 0.0.0.0:5100 app:app
```
`systemctl daemon-reload && systemctl restart palladium-monitor`
#### 邮件 API 端点
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/api/email/status` | 查看当前邮件配置 (不泄露密码) |
| GET | `/api/email/preview` | 渲染报告内容 (不发送, 浏览器内联展示) |
| POST | `/api/email/send` | 手动触发一次 (需 `ALLOW_EMAIL_TRIGGER=true`) |
**注意**: scheduler 在进程内启动, **每个 gunicorn worker 都会尝试启动**; 但用 `_scheduler_started` 锁保证实际只有一个线程在跑, 其余的只是 `time.sleep(86400)` 等下一天, 不影响。
#### 邮件内容示例
每日报告包含:
- **主题**: `[Palladium] 每日报告 YYYY-MM-DD — 利用率 X.X%`
- **正文 (HTML + 纯文本)**: 系统信息 / 当前指标卡片 / 近 24h 趋势统计 + 样本柱状图 / 离线板列表 / 活跃作业列表
- **多部分**: 同时发 HTML 和纯文本, 邮件客户端自动选最合适的渲染
### Z1 主机端(采集 agent
把整个 `palladium-monitor/` 目录 `scp` 到 Z1 主机,然后一键安装:
```bash
sudo ./install_z1_agent.sh \
--url http://<监控服务器IP>:5100/api/collect \
--host <本机标签, e.g. scmp03> \
--env /edatools/vxe/VXE23.03.001/bin/env.csh \
--interval 30
```
卸载:`sudo ./install_z1_agent.sh --uninstall`(保留日志)。
### 故障排查
| 症状 | 检查 |
|------|------|
| 仪表板一直显示示例数据 | `curl http://<monitor>:5100/api/latest` 看最新 snapshot 的 `source` 字段,应为 `collect.py@<host>` 而不是 `sample` |
| Z1 端推送失败 (exit=2) | `tail -50 /var/log/palladium-collect.log`;若 `test_server` 命令找不到,加 `--env /edatools/vxe/VXE23.03.001/bin/env.csh` |
| cron 没跑 | `crontab -l \| grep palladium``grep CRON /var/log/syslog`Linux |
| 推送成功但数据没更新 | 监控服务器 SQLite 写入是同步的,先看 `/api/latest``timestamp`,再 `tail /var/log/palladium-monitor-stderr.log`gunicorn 日志) |
| 想清理老数据 | `curl -X POST 'http://<monitor>:5100/api/cleanup?days=30'` |
| 多台 Z1 一起推 | 给每台用不同的 `--host` 标签,仪表板即可区分来源 |
## 技术栈
- **后端**: Flask 3.0 + Flask-SQLAlchemy + SQLite
- **前端**: Jinja2 模板 + 原生 CSS (暗色主题) + Chart.js (趋势图)
- **解析**: Python re 正则表达式解析 `test_server -short` 输出