以下是为提供的 Python 代码编写的 **Markdown 格式技术文档**,涵盖了模块功能、类说明、方法描述及使用示例。 --- # SSH 连接管理模块技术文档 ## 概述 本模块基于 `asyncssh` 实现了异步 SSH 客户端连接能力,支持通过跳板机(Jump Server)链式连接远程主机,并提供文件传输、命令执行和交互式 Shell 等高级功能。适用于批量运维操作、自动化部署与安全网络环境下的远程控制。 主要特性: - 异步非阻塞 I/O,高并发处理多台服务器 - 支持密码或密钥认证 - 支持多级跳板机穿透 - 提供 SCP 文件上传下载接口 - 支持交互式命令执行(如 Bash) - 封装简洁易用的高层 API 依赖库: ```bash pip install asyncssh shlex ``` --- ## 模块导入说明 ```python import os import sys import time import shlex from traceback import format_exc from contextlib import asynccontextmanager from functools import partial from threading import Thread from appPublic.myTE import tmpTml from appPublic.log import debug, exception import asyncio import asyncssh ``` > 注意:`appPublic.*` 是项目自定义工具包,包含日志记录与模板引擎等功能。 --- ## 核心类说明 ### 1. `SSHServer` 表示一个可通过跳板机访问的目标 SSH 服务器。 #### 初始化参数 | 参数 | 类型 | 说明 | |------|------|------| | `server` | dict | 目标服务器配置,格式见下表 | | `jumpservers` | list[dict] | 跳板机列表(可选),每个元素结构同 `server` | `server` 字典字段说明: | 键名 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `host` | str | 必填 | 主机地址(IP 或域名) | | `username` | str | `'root'` | 登录用户名 | | `port` | int | `22` | SSH 端口 | | `password` | str | `None` | 登录密码(优先级低于密钥) | | `client_keys` | list[str] | `[]` | 私钥路径列表(如 `['~/.ssh/id_rsa']`) | | `passphrase` | str | `None` | 密钥加密口令 | | `jumpservers` | list[dict] | `None` | 内嵌跳板机配置(若未传构造函数参数) | #### 方法 ##### `_connect_server(server: dict, refconn=None) -> asyncssh.SSHClientConnection` 内部方法,建立到指定服务器的连接。 - 若 `refconn` 存在,则通过已有连接隧道建立新连接(用于跳板穿透) - 支持密钥或密码认证自动选择 ##### `get_connector() -> Async Context Manager` 上下文管理器,返回目标主机连接对象,自动处理连接建立与释放。 **示例:** ```python async with ssh_server.get_connector() as conn: result = await conn.run('ls -l') print(result.stdout) ``` > 自动关闭所有跳板机连接,异常时捕获并记录日志。 --- ### 2. `SSHNode` 增强版 SSH 节点,封装完整生命周期管理与多种操作接口。 #### 初始化参数 | 参数 | 类型 | 默认值 | 说明 | |------|------|--------|------| | `host` | str | 必填 | 目标主机地址 | | `username` | str | `'root'` | 用户名 | | `port` | int | `22` | SSH 端口 | | `password` | str | `None` | 登录密码 | | `client_keys` | list[str] | `[]` | 客户端私钥路径 | | `passphrase` | str | `None` | 私钥解密口令 | | `jumpers` | list[dict] | `[]` | 跳板机列表 | #### 属性 - `conn`: 当前节点主连接 (`asyncssh.SSHClientConnection`) - `jumper_conns`: 所有跳板连接列表 - `batch_cmds`: 待执行命令队列(暂未完全实现) #### 方法 | 方法 | 功能 | |------|------| | `info()` → dict | 返回当前节点信息快照 | | `asjumper()` → list[dict] | 返回可用于其他节点跳板的配置列表 | | `set_jumpers(jumpers)` | 动态设置跳板机 | | `connect()` | 建立完整连接链(跳板 + 主机) | | `close()` | 关闭所有连接资源 | | `run(cmd, ...)` | 执行单条命令(自动连接/关闭) | | `_cmd`, `_run`, `_process`, `_l2r`, `_r2l` | 内部操作封装 | ##### `run(cmd, input=None, stdin=None, stdout=None)` 执行远程命令,支持以下特殊语法: - `l2r `:本地 → 远程复制(SCP) - `r2l `:远程 → 本地复制(SCP) 否则调用 `conn.run()` 执行普通命令。 ##### `_xcmd(cmd, xmsgs=[], ns={}, show_input=None, show_stdout=None)` 执行交互式命令,支持定时输入模拟。 - `xmsgs`: 输入消息列表,格式 `[ (delay_sec, template_string), ... ]` - `ns`: 模板变量命名空间 - `show_input`, `show_stdout`: 回调函数,用于输出监控 > 示例:自动登录 CLI 工具、数据库等需要逐步输入的场景。 --- ### 3. `SSHNodes` 批量管理多个 `SSHNode` 的容器类,支持并行执行。 #### 初始化参数 | 参数 | 类型 | 说明 | |------|------|------| | `nodes` | list[str] | 主机名/IP 列表 | | `username` | str | 统一用户名 | | `port` | int | 统一端口 | | `jumpers` | list[dict] | 共享跳板机配置 | #### 方法 | 方法 | 功能 | |------|------| | `append_cmd(cmd, stdin, stdout)` | 添加待批处理命令 | | `run(cmd, ...)` | 并发运行命令于所有节点 | | `exe_batch()` | 执行预设批处理命令队列(**注意:当前存在 bug**) | > 使用 `asyncio.gather(..., return_exceptions=True)` 避免单个失败中断整体流程。 #### 示例 ```python hosts = ['192.168.1.10', '192.168.1.11'] jump = {"host": "jumper.example.com", "username": "jumpuser", "port": 22} cluster = SSHNodes(hosts, jumpers=[jump]) results = await cluster.run("uptime") for r in results: if isinstance(r, Exception): print("Error:", r) else: print(r.stdout.strip()) ``` --- ### 4. `SSHBash` 实现交互式远程 Bash Shell 会话,支持实时输入输出转发。 #### 构造函数 ```python SSHBash(node: SSHNode, loop=None) ``` - `node`: 已配置的 `SSHNode` 实例 - `loop`: 可选事件循环(默认使用当前) 内部启动独立线程运行子事件循环,避免阻塞主线程。 #### 核心方法 ##### `run(read_co, write_co)` 启动交互式 Bash 会话。 - `read_co`: 异步可调用对象,用于读取用户输入(例如从 `stdin`) - `write_co`: 异步回调,用于写入输出内容(如打印到终端) > 底层使用 `create_process('bash', term_type='xterm-256color')` ##### `feed_stdin(f)` 将输入数据推送到远程进程 stdin。 ##### `exit()` 清理资源:关闭连接、停止子线程事件循环。 #### 使用示例 ```python async def read_input(): return os.read(sys.stdin.fileno(), 65535) async def write_output(data): sys.stdout.write(data.decode('utf-8')) sys.stdout.flush() bash = SSHBash(my_ssh_node) await bash.run(read_input, write_output) ``` --- ### 5. `SshConnector` 轻量级连接包装器,提供更直观的操作接口。 > ⚠️ **Bug 提示**:`l2r` 方法中 `recurse=Tree` 应为 `recurse=True` #### 方法 | 方法 | 功能 | |------|------| | `r2l(rf, lf)` | 下载文件:远程 → 本地 | | `l2r(lf, rf)` | 上传文件:本地 → 远程 | | `run_process(*args, **kw)` | 创建远程进程 | | `run(cmdline, ...)` | 执行命令并返回结果 | --- ## 辅助函数与入口点 ### `main()` 命令行交互入口,演示如何动态输入命令对多个主机批量执行。 ```bash python script.py "df -h" host1 host2 ... ``` > 当前版本进入无限循环等待用户输入。 ### `test_sshbash()` 测试交互式 Bash 功能的示例函数。 --- ## 已知问题与改进建议 | 问题 | 描述 | 建议修复 | |------|------|---------| | `SSHNodes.__init__` 拼写错误 | `usernmae` → `username` | 更正拼写 | | `exe_batch()` 中 `return_excetion=True` | 拼写错误导致异常不被捕获 | 改为 `return_exceptions=True` | | `exe_batch()` 在 `gather` 后仍有代码 | `return` 后不会执行后续行 | 移动 `for` 循环至 `gather` 之后 | | `SshConnector.l2r` 中 `self.comm` | 应为 `self.conn` | 修正属性引用 | | `show_result()` 中变量 `e` 未定义 | `print('Exception:', e)` 报错 | 改为 `print('Exception:', x)` | | `recurse=Tree` | 应为布尔值 `True` | 修改为 `recurse=True` | --- ## 总结 该模块构建了一个灵活高效的异步 SSH 操作框架,特别适合在受限网络环境中通过跳板机批量管理服务器。结合 `asyncssh` 的强大功能,实现了文件传输、命令执行、交互式 Shell 等核心运维需求。 建议进一步完善单元测试、增加连接池、超时控制与重试机制以提升稳定性。 --- 📌 **维护建议**: - 添加类型注解(Type Hints) - 补充 docstring 文档字符串 - 分离配置加载逻辑 - 增加连接健康检查机制 --- ✅ **适用场景**: - 自动化部署系统 - 多数据中心运维脚本 - DevOps 流水线中的远程操作环节 - 内网服务器集中管理平台 --- *文档版本:v1.0* *最后更新:2025年4月5日*