82426b1941
新增侧栏「宝塔面板」菜单、代理 API 与连接配置页;通过 SSH 读写子机 api.json 自动写入凭据,5 分钟后台重试,含审计修复、检测缓存与并发锁。 Co-authored-by: Cursor <cursoragent@cursor.com>
81 lines
3.8 KiB
Markdown
81 lines
3.8 KiB
Markdown
# Changelog — 宝塔 SSH 自动获取 API
|
||
|
||
**日期**:2026-06-20
|
||
|
||
## 摘要
|
||
|
||
通过 SSH 在子机自动读取/开启宝塔 API(`api.json`),加密写入 Nexus `extra_attrs.bt_panel`;未成功时每 5 分钟后台重试,适配「先 SSH、后装宝塔」场景。
|
||
|
||
## 动机
|
||
|
||
- 2000+ 子机手工填 `base_url` + API Key 不可运维
|
||
- 装机窗口内宝塔可能尚未安装,需后台轮询而非绑 WebSSH
|
||
- 中心 IP 白名单需自动追加到子机 `limit_addr`
|
||
|
||
## 涉及文件
|
||
|
||
| 层 | 路径 |
|
||
|----|------|
|
||
| 远程脚本 | `server/infrastructure/btpanel/ssh_bootstrap.py` |
|
||
| 状态机 | `server/infrastructure/btpanel/bootstrap_state.py` |
|
||
| 并发锁 | `server/infrastructure/btpanel/bootstrap_lock.py` |
|
||
| 中心 IP | `server/infrastructure/btpanel/source_ip.py` |
|
||
| SSH 检测 | `server/infrastructure/btpanel/ssh_login.py` |
|
||
| 调度 | `server/application/services/btpanel_bootstrap_schedule.py` |
|
||
| 后台 | `server/background/bt_panel_bootstrap_loop.py` |
|
||
| 服务/API | `server/application/services/btpanel_service.py`, `server/api/btpanel.py` |
|
||
| 触发 | `server/api/servers.py`(创建/凭据轮询成功) |
|
||
| 批量 | `server/application/services/server_batch_service.py`(`bt-panel-bootstrap`) |
|
||
| 配置 | `server/config.py`(`BT_PANEL_*`) |
|
||
| 前端 | `frontend/src/pages/btpanel/BtPanelSettingsPage.vue`, `frontend/src/api/btpanel.ts` |
|
||
| 测试 | `tests/test_btpanel_ssh_bootstrap.py`, `tests/test_btpanel_bootstrap_loop.py`, `tests/test_btpanel_ssh_login.py`, `tests/test_btpanel_get_config.py` |
|
||
|
||
## 配置项(settings 表 / `.env` `NEXUS_` 前缀)
|
||
|
||
- `bt_panel_source_ip` — 中心调用 IP(优先于 DNS)
|
||
- `bt_panel_auto_bootstrap_enabled` — 全局自动获取(默认 `true`)
|
||
- `bt_panel_bootstrap_batch` — 每轮最多处理台数(默认 20)
|
||
- `bt_panel_bootstrap_interval` — 轮询间隔秒(默认 300)
|
||
|
||
## 迁移 / 重启
|
||
|
||
- 无 DB 迁移(状态存 `servers.extra_attrs`,含 `bt_installed` 缓存)
|
||
- 需重启 API 以注册 `bt_panel_bootstrap_loop`(primary worker)
|
||
|
||
## 验证
|
||
|
||
```bash
|
||
.venv/bin/pytest tests/test_btpanel_*.py -q
|
||
cd frontend && npx vite build
|
||
```
|
||
|
||
- 新服务器创建 → `bootstrap_state=pending`,立即试 1 次
|
||
- 无宝塔目录 → `installing`,5min 后再试
|
||
- 成功 → `ready`,loop 跳过
|
||
- SSH 认证失败 → `failed`,停止直至手动「立即 SSH 获取」
|
||
|
||
---
|
||
|
||
## 审计修复(同日增补)
|
||
|
||
### 严重
|
||
|
||
1. **后台 loop 误扫全库**:未入库引导的服务器因默认 `pending` 被 eligible → 仅已有 `bt_panel` 块且显式 `pending`/`installing` + `next_attempt_at` 到期才进 loop。
|
||
2. **`Permission denied` 误判永久失败**:区分 SSH 认证 vs 远程写 `api.json` 权限错误。
|
||
3. **`ssh_login` 使用 `result.success`**:`exec_ssh_command` 返回 `status` 字段,导致检测/一键登录异常 → 已改 `status == "success"`。
|
||
|
||
### 中等
|
||
|
||
4. **手动获取覆盖 `disabled`**:手动「立即获取」不再强制 `auto_bootstrap=true`。
|
||
5. **空凭据标 ready**:远程 JSON 空 `base_url`/`api_key` → `bootstrap_empty_credentials` 可重试。
|
||
6. **loop 时间解析**:`run_bootstrap_tick` 改用 `_parse_iso`,避免畸形时间打挂整轮。
|
||
7. **中心 IP 校验**:全局设置非空须合法 IPv4/IPv6。
|
||
8. **UI 状态**:`bootstrap_state=null` 显示「未启用」;`auto_bootstrap` 仅 `true` 为开。
|
||
|
||
### 体验 / 性能(本轮)
|
||
|
||
9. **`get_config` SSH 节流**:仅 `pending`/`installing` 或 `?refresh_bt_installed=true` 时 SSH 检测;结果缓存 `extra_attrs.bt_panel.bt_installed`。
|
||
10. **批量初始化确认**:连接配置页批量操作前 `v-dialog` 二次确认。
|
||
11. **per-server 锁**:`bootstrap_lock` 防止即时触发与 5min loop 并发双 SSH。
|
||
12. **loop 日志**:`run_bootstrap_tick` 仅统计 `ok=true` 成功台数。
|