Netmiko 源码解析
1. 源码结构概览
Netmiko 的代码库主要分为以下核心模块:
netmiko/
├── base_connection.py # 连接基类(核心逻辑)
├── cisco/ # Cisco 设备实现类
├── juniper/ # Juniper 设备实现类
├── hp_procurve/ # HP 设备实现类
├── ... # 其他厂商目录
├── ssh_dispatcher.py # 设备类型与类的映射
├── utilities.py # 辅助函数(如处理输出)
└── exceptions.py # 自定义异常类
2. 核心类解析
BaseConnection
类(base_connection.py)
- 作用:所有设备连接类的基类,定义了 SSH 连接管理、命令发送、模式切换等核心方法。
- 关键方法:
class BaseConnection(object):def __init__(self, **kwargs): # 初始化参数(host、username、password等)self.host = kwargs.get('host')self.establish_connection() # 建立 SSH 连接def establish_connection(self):# 调用 Paramiko 的 SSHClient 创建连接self.remote_conn = paramiko.SSHClient()self.remote_conn.connect(**ssh_params)def send_command(self, command, **kwargs):# 发送命令,等待输出完成self._write_channel(command + '\n')output = self._read_channel()return outputdef _read_channel(self):# 读取 SSH 通道的输出(处理缓冲和超时)while not output.endswith(self.prompt):time.sleep(0.1)output += self.remote_conn.recv(65535).decode()return output
厂商子类(如 CiscoIosBase)
- 作用:继承
BaseConnection
,针对特定设备定制行为(如提示符、模式切换命令)。class CiscoIosBase(BaseConnection):def session_preparation(self):# 进入 enable 模式,设置终端长度self.enable()self.set_terminal_width()def enable(self, cmd='enable', pattern='password'):# 发送 enable 命令并处理密码输入self.write_channel(cmd + '\n')self.write_channel(self.secret + '\n')
3. 关键流程分析
连接初始化流程
-
设备类型映射:
- 用户指定
device_type
(如cisco_ios
)。 ssh_dispatcher.py
中的ConnectHandler
函数根据类型选择对应的厂商类。
def ConnectHandler(**kwargs):device_type = kwargs['device_type']klass = ssh_dispatcher(device_type) # 返回 CiscoIosBase 等类return klass(**kwargs)
- 用户指定
-
SSH 连接建立:
- 调用
Paramiko
库创建 SSH 会话,处理认证(密码或密钥)。 - 设置会话参数(超时、终端类型)。
- 调用
-
会话准备:
- 自动执行
session_preparation()
(如进入 enable 模式、关闭分页)。
- 自动执行
命令执行流程(以 send_command
为例)
-
发送命令:
def send_command(self, command, **kwargs):self._write_channel(command + '\n') # 向通道写入命令
-
读取输出:
- 通过
_read_channel()
循环读取 SSH 通道数据,直到匹配设备提示符。 - 使用
delay_factor
和max_loops
控制等待时间,防止超时。
- 通过
-
输出处理:
- 清除命令回显(如去除输入的
show version
字符串)。 - 可选使用 TextFSM 或 Genie 进行结构化解析。
- 清除命令回显(如去除输入的
配置模式处理(send_config_set
)
- 进入配置模式:
- 自动发送
configure terminal
(或其他厂商等效命令)。
- 自动发送
- 逐行发送配置:
for cmd in config_commands:self.send_command(cmd)
- 退出配置模式:
- 发送
exit
或end
命令,返回特权模式。
- 发送
4. 关键设计思想
多态与继承
- 所有厂商类继承自
BaseConnection
,重写特定方法(如enable()
)以适配设备差异。 - 例如,Juniper 设备的配置模式使用
configure private
,而 Cisco 使用configure terminal
:class JuniperJunosBase(BaseConnection):def config_mode(self, config_command='configure private'):self.write_channel(config_command + '\n')
SSH 通道管理
- 使用 Paramiko 的
SSHClient
创建通道,通过_read_channel()
和_write_channel()
实现读写分离。 - 缓冲区和超时机制确保输出完整性。
异常处理
- 自定义异常类(如
NetmikoTimeoutException
)在关键节点抛出:def _read_channel(self):if time.time() > end_time:raise NetmikoTimeoutException("读取超时!")
5. 调试与扩展
调试技巧
- 启用日志:
import logging logging.basicConfig(level=logging.DEBUG)
- 修改源码:在关键方法中添加
print
语句跟踪执行流程。
扩展新设备支持
- 创建子类:
class CustomDevice(BaseConnection):def session_preparation(self):self.enable()self.set_terminal_width()
- 注册设备类型:
def ssh_dispatcher(device_type):if device_type == 'custom_device':return CustomDevice
6. 源码分析工具建议
- IDE 调试:使用 PyCharm 或 VS Code 设置断点跟踪执行。
- 代码跳转:结合
ctags
或Go to Definition
快速导航代码。 - UML 生成:生成类图(如
pyreverse
)直观查看继承关系。
通过源码分析,你可以更灵活地解决复杂问题(如适配非标准设备)、优化性能(调整超时参数),或贡献代码到开源社区。建议结合官方文档和实际调试逐步深入。