修复Cisco路由器SSH连接问题并完善配置代码求助
Netmiko连接Cisco路由器超时及代码错误修复
错误现象
SSH连接成功后触发超时,报错信息如下:
INFO:paramiko.transport:Connected (version 1.99, client Cisco-1.25) INFO:paramiko.transport:Authentication (password) successful! INFO:root:Connection established ERROR:root:An error occurred: Timed-out reading channel, data not available. INFO:root:The connection has concluded
同时收到net_connect.disconect()未定义的提示。
问题分析与修复
原代码存在命令格式错误、连接管理不当、功能缺失等问题,以下是修复后的完整代码及关键说明:
修复后的完整代码
from netmiko import ConnectHandler import getpass import difflib import logging # 日志配置 logging.basicConfig(level=logging.INFO) # 保存配置到本地文件 def save_config_to_file(config, filename): with open(filename, 'w') as config_file: config_file.write(config) logging.info(f'Configuration saved to {filename}') # 对比并显示配置差异 def show_differences(config1_label, config1, config2_label, config2): difference = difflib.Differ() diff = list(difference.compare(config1.splitlines(), config2.splitlines())) for line in diff: if line.startswith('- '): logging.info(f'Present in {config1_label}: {line[2:]}') elif line.startswith('+ '): logging.info(f'Present in {config2_label}: {line[2:]}') # 配置设备(含环回、物理接口、OSPF) def configure_device(net_connect): # 进入特权模式 net_connect.enable() # 配置命令列表(无需手动加换行符,Netmiko自动处理模式切换) config_commands = [ # 环回接口配置 'interface Loopback0', 'ip address 192.168.57.101 255.255.255.0', 'exit', # 物理接口0配置(启用接口) 'interface GigabitEthernet0/0', 'ip address 192.168.58.101 255.255.255.0', 'no shutdown', 'exit', # 物理接口1配置(启用接口) 'interface GigabitEthernet0/1', 'ip address 192.168.59.101 255.255.255.0', 'no shutdown', 'exit', # ACL配置(修正为Cisco反掩码) 'ip access-list extended MY_ACL', 'permit ip 192.168.56.130 0.0.0.255 any', 'deny ip any any', 'exit', # OSPF配置及网段宣告 'router ospf 1', 'router-id 192.168.57.101', 'network 192.168.57.0 0.0.0.255 area 0', 'network 192.168.58.0 0.0.0.255 area 0', 'network 192.168.59.0 0.0.0.255 area 0', 'exit' ] # 发送配置命令,自动进入全局配置模式 output = net_connect.send_config_set(config_commands) print(output) # 保存配置到设备NVRAM net_connect.save_config() # 主逻辑 def main(): host = '192.168.56.101' username = input('Please enter your username: ') password = getpass.getpass('Please enter your password: ') secret = 'cisco' choice = input('Would you like to connect by using telnet or ssh? ') if choice.lower() == 'telnet': device_type = 'cisco_ios_telnet' elif choice.lower() == 'ssh': device_type = 'cisco_ios' else: raise ValueError('Invalid - Please choose either telnet or ssh: ') device = { 'device_type': device_type, 'host': host, 'username': username, 'password': password, 'secret': secret, 'port': 22 if device_type == 'cisco_ios' else 23, 'timeout': 100, 'fast_cli': False, # 禁用快速CLI模式,提升Cisco设备兼容性 } try: # with语句自动管理连接生命周期,无需手动断开 with ConnectHandler(**device) as net_connect: logging.info('Connection established') # 执行设备配置 configure_device(net_connect) # 获取并保存运行配置 running_configuration = net_connect.send_command('show running-config') local_config_file_name = 'local_config.txt' save_config_to_file(running_configuration, local_config_file_name) logging.info(f'The configuration has been saved to {local_config_file_name}') # 对比本地与设备配置 try: with open(local_config_file_name, 'r') as local_config_file: local_config = local_config_file.read() if running_configuration and local_config: if running_configuration == local_config: logging.info('The running configuration is the same as the local configuration') else: logging.warning('The running configuration does not match the local configuration: ') show_differences('Running Config', running_configuration, 'Local Config', local_config) else: logging.error('Failed to access configurations') except FileNotFoundError: logging.error(f'The local configurations file, {local_config_file_name}, could not be found') except Exception as e: logging.error(f'An error occurred: {e}') logging.info('The connection has concluded') if __name__ == "__main__": main()
关键修复点
- 修正命令格式:移除配置命令中的
\n及手动添加的en/conf t,send_config_set会自动进入全局配置模式,多余的换行符会导致设备响应异常引发超时。 - 修复连接管理:原代码在
with块外调用disconnect(),with语句会自动关闭连接,此时net_connect已失效;移除手动断开逻辑,依赖with自动管理。 - 补充OSPF配置:添加OSPF进程号、router-id及正确的网段宣告(使用Cisco反掩码)。
- 启用物理接口:物理接口默认处于shutdown状态,添加
no shutdown命令启用接口。 - 修正ACL掩码:Cisco ACL需使用反掩码,将
255.255.255.0改为0.0.0.255。 - 优化差异显示:原函数直接打印完整配置字符串,修改为传入标签,避免输出混乱。
- 添加设备配置保存:调用
save_config()将配置写入NVRAM,防止重启丢失。 - 提升兼容性:添加
fast_cli=False,禁用快速CLI模式,减少与Cisco设备的交互超时概率。
内容的提问来源于stack exchange,提问作者Louis16
相关产品推荐
相关产品推荐

