# 执行计划：自动化部署测试模块

> **版本**：v1.0  
> **创建日期**：2026-08-12  
> **来源**：`_PRD_需求文档_自动化部署测试模块.md`  
> **状态**：待执行

---

## 一、任务分解

| 阶段 | 任务 | 预计文件数 | 优先级 |
|------|------|-----------|--------|
| Phase 1 | 后端依赖 + 数据模型（4 模型 + 注册） | 5 文件 | P0 |
| Phase 2 | Pydantic Schemas | 1 文件 | P0 |
| Phase 3 | SSH 执行器（核心交互式输入处理） | 1 文件 | P0 |
| Phase 4 | 部署服务（业务逻辑 + 线程管理） | 1 文件 | P0 |
| Phase 5 | API 路由（CRUD + WebSocket） + main.py 注册 | 2 文件 | P0 |
| Phase 6 | 前端类型定义 + API 模块 | 2 文件 | P0 |
| Phase 7 | 前端路由 + 侧边栏菜单 | 2 文件 | P0 |
| Phase 8 | 前端视图（4 页面） | 5 文件 | P0 |
| Phase 9 | 验证：启动服务 + 冒烟测试 | — | P1 |

---

## 二、详细实现步骤

### Phase 1: 依赖 + 数据模型

**文件**：`backend/requirements.txt`（修改）
- 追加 `paramiko==3.4.0`

**文件**：`backend/app/models/deploy_server.py`（新建）
- `DeployServer` 模型，表名 `deploy_servers`
- 字段：id(String64 PK, `generate_id("srv")`), name, host, port(default 22), username, password_encrypted, auth_type, private_key(nullable), status, description, created_at, updated_at
- 密码加密：`encrypt_password()` / `decrypt_password()` 方法（Fernet）

**文件**：`backend/app/models/deploy_script.py`（新建）
- `DeployScript` 模型，表名 `deploy_scripts`
- 字段：id(String64 PK), name, description, server_id(FK → deploy_servers), remote_command, work_dir(nullable), timeout(default 3600), expect_answers(JSON), created_at, updated_at
- `server` 关系：`relationship("DeployServer", back_populates="scripts")`

**文件**：`backend/app/models/deploy_execution.py`（新建）
- `DeployExecution` 模型，表名 `deploy_executions`
- 快照字段：script_id, server_id, script_name, server_name, server_host, remote_command
- 状态字段：status(pending/running/completed/failed/cancelled), start_time, end_time, duration, exit_code(nullable), error_message(nullable Text), trigger_by, created_at
- `script` 关系：`relationship("DeployScript")`

**文件**：`backend/app/models/deploy_log.py`（新建）
- `DeployLog` 模型，表名 `deploy_logs`
- 字段：id(String64 PK), execution_id(FK → deploy_executions), timestamp, level, message(Text), is_sensitive

**文件**：`backend/app/models/__init__.py`（修改）
- 导入 4 个新模型，加入 `__all__`

### Phase 2: Pydantic Schemas

**文件**：`backend/app/schemas/deploy.py`（新建）
- `DeployServerBase/Create/Update/Response/ListResponse`
- `ExpectAnswer`（单条规则：trigger, trigger_type, answer, timeout, order, sensitive, description）
- `DeployScriptBase/Create/Update/Response/ListResponse`
- `DeployExecutionCreate/Response/ListResponse`
- `DeployLogResponse/ListResponse`

### Phase 3: SSH 执行器

**文件**：`backend/app/executors/deploy_executor.py`（新建）
- `DeployExecutor` 类
- `__init__(server_config, script_config)`：接收纯 dict 配置
- `execute(execution_id, ev_loop, broadcast_fn)`：主执行方法
  - SSH 连接（paramiko.SSHClient + AutoAddPolicy）
  - 打开交互式 PTY（`invoke_shell(term='xterm')` + `get_pty=True`）
  - 单线程轮询循环：
    - `channel.recv(4096)` 读取输出，追加到 buffer
    - 每行输出通过 `asyncio.run_coroutine_threadsafe(broadcast_fn(...), ev_loop)` 广播
    - 按 order 遍历未匹配的 `expect_answers`，匹配触发词则发送应答
    - `time.sleep(0.05)` 防忙等
  - 完成检测：`channel.exit_status_ready()` → `recv_exit_status()`
  - 超时保护：总执行时间超 timeout 时退出
- `cancel()`：设 `_cancelled=True`，`channel.close()`
- `close()`：清理 SSH 连接

### Phase 4: 部署服务

**文件**：`backend/app/services/deploy_service.py`（新建）
- `DeployService` 类
- 服务器 CRUD：`list_servers`, `get_server`, `create_server`(加密密码), `update_server`(密码留空不修改), `delete_server`, `test_server_connection`
- 脚本 CRUD：`list_scripts`, `get_script`, `create_script`, `update_script`, `delete_script`
- 执行 CRUD：`list_executions`, `get_execution`, `get_execution_logs`, `delete_execution`
- 核心执行：
  - `create_execution`：建执行记录，状态 pending
  - `run_execution`：状态→running，起专用线程，`loop.run_in_executor(None, join)`
  - `cancel_execution`：调用 executor.cancel()
- 日志双通道：WebSocket 实时广播 + 逐条/批量落库

### Phase 5: API 路由

**文件**：`backend/app/routers/deploy.py`（新建）

| 方法 | 路径 | 说明 |
|------|------|------|
| GET | /api/deploy/servers | 服务器列表 |
| POST | /api/deploy/servers | 新增服务器 |
| GET | /api/deploy/servers/{id} | 服务器详情 |
| PUT | /api/deploy/servers/{id} | 编辑服务器 |
| DELETE | /api/deploy/servers/{id} | 删除服务器 |
| POST | /api/deploy/servers/{id}/test | 测试 SSH 连接 |
| GET | /api/deploy/scripts | 脚本列表（支持 server_id 筛选） |
| POST | /api/deploy/scripts | 新增脚本配置 |
| GET | /api/deploy/scripts/{id} | 脚本详情 |
| PUT | /api/deploy/scripts/{id} | 编辑脚本 |
| DELETE | /api/deploy/scripts/{id} | 删除脚本 |
| GET | /api/deploy/executions | 执行记录列表 |
| POST | /api/deploy/executions | 创建执行 |
| POST | /api/deploy/executions/{id}/run | 执行部署 |
| POST | /api/deploy/executions/{id}/cancel | 取消执行 |
| GET | /api/deploy/executions/{id} | 执行详情 |
| DELETE | /api/deploy/executions/{id} | 删除执行记录 |
| GET | /api/deploy/executions/{id}/logs | 执行日志 |
| WS | /api/deploy/ws/executions/{id} | WebSocket 实时日志 |

**文件**：`backend/app/main.py`（修改）
- 导入 `from app.routers import deploy`
- 注册 `app.include_router(deploy.router, prefix="/api/deploy", tags=["自动化部署测试"])`

### Phase 6: 前端类型 + API

**文件**：`frontend/src/types/deploy.ts`（新建）
- `DeployServer`, `ExpectAnswer`, `DeployScript`, `DeployExecution`, `DeployLog`

**文件**：`frontend/src/api/deploy.ts`（新建）
- `deployApi` 对象，全量 API 调用

### Phase 7: 前端路由 + 菜单

**文件**：`frontend/src/router/index.ts`（修改）
- 新增 `/deploy` 父路由 + 子路由

**文件**：`frontend/src/App.vue`（修改）
- 新增 `el-sub-menu` 侧边栏菜单，图标导入，pageTitle 映射

### Phase 8: 前端视图

**文件**：`frontend/src/views/deploy/index.vue`（新建）
- 父容器 `<router-view/>`

**文件**：`frontend/src/views/deploy/DeployServers.vue`（新建）
- 服务器列表 + 新增/编辑对话框（含密码加密、认证方式切换、连接测试）

**文件**：`frontend/src/views/deploy/DeployScripts.vue`（新建）
- 脚本列表 + 编辑对话框（脚本信息 + 交互式应答编辑器）

**文件**：`frontend/src/views/deploy/DeployExecutions.vue`（新建）
- 执行中心：选择脚本 → 执行 → 实时日志终端（深色主题、自动滚动）+ 历史记录列表

**文件**：`frontend/src/views/deploy/DeployExecutionDetail.vue`（新建）
- 执行详情 + 全量日志回看

---

## 三、关键设计决策

| 决策 | 选择 | 理由 |
|------|------|------|
| SSH 库 | paramiko（同步） | 项目的 `deploy_to_560.py` 已在使用，同步 API 避免 asyncio 问题 |
| 交互式输入 | 预设触发词→应答 | 用户在规划阶段已确认此方案 |
| 执行线程 | 专用 `threading.Thread` | 复用 `execution_service.py` 已验证的模式，避免 ThreadPoolExecutor 死锁 |
| 日志实时推送 | WebSocket（ConnectionManager） | 复用现有基础设施，按 execution_id 分组广播 |
| 密码加密 | Fernet 对称加密 | 复现 `device_sim_service.py` 的加密方案 |
| 脚本来源 | 目标服务器已有脚本 | 用户在规划阶段已确认此方案 |

---

## 四、验收标准

1. 后端 `/docs` 自动文档出现 `/api/deploy` 路由组
2. 数据库自动创建 `deploy_servers`, `deploy_scripts`, `deploy_executions`, `deploy_logs` 四张表
3. 侧边栏出现"自动化部署测试"父菜单，含 3 个子菜单
4. 新增服务器 → 测试连接成功
5. 新建脚本（含交互应答规则）→ 执行部署 → 实时日志流式显示 → 自动应答发送 → 执行完成
6. 执行中可取消，历史记录可回看
7. `frontend npm run build` 类型检查 + 打包通过