使用Paramiko+CiscoConfParse读远程配置及Rancid脚本技术咨询
嘿,我来帮你搞定这两个需求——先说说怎么用Paramiko搭配CiscoConfParse读取远程思科设备的配置,再把你那套和Rancid交互的脚本补全优化一下~
一、用Paramiko + CiscoConfParse读取远程思科配置
这个思路很清晰:先用Paramiko建立SSH连接到设备,拉取完整配置(比如show running-config),再把配置内容传给CiscoConfParse做结构化解析,不用自己写一堆正则来处理配置层级。
完整示例代码
import paramiko from ciscoconfparse import CiscoConfParse def get_and_parse_cisco_config(device_ip, username, password): # 1. 初始化SSH客户端并建立连接 ssh_client = paramiko.SSHClient() ssh_client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) try: ssh_client.connect( hostname=device_ip, username=username, password=password, look_for_keys=False, allow_agent=False ) # 2. 执行命令获取设备配置 stdin, stdout, stderr = ssh_client.exec_command("show running-config") config_output = stdout.read().decode('utf-8') # 检查是否有错误输出 error_msg = stderr.read().decode('utf-8') if error_msg: print(f"获取配置时出错: {error_msg}") return None # 3. 用CiscoConfParse解析配置内容 parsed_config = CiscoConfParse(config_output.splitlines()) return parsed_config except Exception as e: print(f"连接或执行命令失败: {str(e)}") return None finally: # 确保SSH连接被关闭,避免资源泄漏 if ssh_client.get_transport() and ssh_client.get_transport().is_active(): ssh_client.close() # 调用示例 if __name__ == "__main__": config = get_and_parse_cisco_config("192.168.1.1", "admin", "your_password") if config: # 举个实用例子:提取所有access模式接口及其所属VLAN access_intfs = config.find_objects_w_child( parentspec=r'^interface', childspec=r'switchport mode access' ) for intf in access_intfs: vlan_match = intf.re_search_children(r'switchport access vlan (\d+)') if vlan_match: print(f"接口 {intf.text.strip()} 属于VLAN {vlan_match[0].group(1)}")
关键细节提醒
- 加上
look_for_keys=False和allow_agent=False可以跳过本地密钥和代理的自动尝试,适合纯密码登录的场景 - CiscoConfParse会自动识别思科配置的层级结构,你可以用它的
find_objects、re_search_children等方法快速定位配置项,比自己写正则高效太多
二、完善你的Rancid VLAN查询脚本
看你已经写了个雏形,我帮你补全逻辑、加上异常处理和资源清理,让脚本更健壮:
import paramiko def get_vlans(): # 这里是你调用IPAM API获取新VLAN的逻辑,示例返回VLAN ID列表 return [100, 200, 300] def check_rancid_for_vlan(rancid_host, username, password): vlans = get_vlans() client = paramiko.SSHClient() client.set_missing_host_key_policy(paramiko.AutoAddPolicy()) results = {} try: client.connect( rancid_host, username=username, password=password, look_for_keys=False, allow_agent=False ) for vlan_id in vlans: # 执行Rancid的device q命令 cmd = f"device q {vlan_id}" stdin, stdout, stderr = client.exec_command(cmd) # 读取命令输出和错误信息 output = stdout.read().decode('utf-8').strip() error = stderr.read().decode('utf-8').strip() if error: results[vlan_id] = {"status": "error", "message": error} else: # 根据Rancid实际输出格式解析设备信息,这里是示例逻辑 device_info = {} if output: for line in output.splitlines(): if "Device Name:" in line: device_info["name"] = line.split("Device Name:")[1].strip() if "Device IP:" in line: device_info["ip"] = line.split("Device IP:")[1].strip() results[vlan_id] = device_info if device_info else {"status": "no_matching_devices"} except Exception as e: print(f"连接Rancid服务器失败: {str(e)}") # 给所有VLAN标记连接失败状态 for vlan_id in vlans: results[vlan_id] = {"status": "connection_failed", "message": str(e)} finally: # 确保关闭SSH连接 if client.get_transport() and client.get_transport().is_active(): client.close() return results # 调用示例 if __name__ == "__main__": rancid_results = check_rancid_for_vlan("rancid-server-ip", "rancid-user", "rancid-pass") for vlan, info in rancid_results.items(): print(f"VLAN {vlan}: {info}")
优化点说明
- 用
try/finally块确保不管有没有异常,SSH连接都会被关闭,避免资源泄漏 - 给每个VLAN的查询结果添加了状态标记,方便后续处理错误场景
- 解析Rancid输出的部分需要你根据
device q命令的实际输出格式调整,比如如果输出是JSON或者特定分隔符格式,要对应修改解析逻辑
内容的提问来源于stack exchange,提问作者CEamonn
相关产品推荐
相关产品推荐

