6726524c50
- 修复删除快照时 AttributeError: SQLAlchemy.get_or_404 (低版本兼容) - UI/标题/邮件主题从 'Palladium Z1 Monitor' 改为 'Palladium Monitor'
288 lines
11 KiB
Markdown
288 lines
11 KiB
Markdown
# 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` 输出
|