OSPF邻居状态监控这事,靠人工定期登录设备看display ospf peer brief不太现实,设备多了根本看不过来。用Python写个脚本定时采集所有设备的OSPF邻居状态,发现Full以外的状态就告警,比人工巡检靠谱多了。
思路很简单:用netmiko批量SSH登录设备,执行display命令,解析输出提取邻居状态,跟上次的结果做对比,有变化就发告警。
先定义设备清单,用yaml文件管理:
devices: - name: core-sw-01 ip: 10.1.1.1 username: admin password: Admin@123 type: huawei - name: core-sw-02 ip: 10.1.1.2 username: admin password: Admin@123 type: huawei - name: access-sw-01 ip: 10.1.2.1 username: admin password: Admin@123 type: h3c
核心采集脚本:
import yamlfrom netmiko import ConnectHandlerimport reimport timeimport smtplibfrom email.mime.text import MIMETextdef load_devices(yaml_file): with open(yaml_file, 'r') as f: config = yaml.safe_load(f) return config['devices']def get_ospf_neighbors(device): vendor_type = device['type'] if vendor_type == 'huawei': cmd = 'display ospf peer brief' elif vendor_type == 'h3c': cmd = 'display ospf peer brief' elif vendor_type == 'ruijie': cmd = 'show ip ospf neighbor' else: cmd = 'display ospf peer brief'# netmiko的device_type命名规则:厂商名后缀_ssh表示SSH连接# 注意h3c对应hp_comware,ruijie对应ruijie_os,不是简单加_ssh type_map = { 'huawei': 'huawei', 'h3c': 'hp_comware', 'ruijie': 'ruijie_os', } conn_params = { 'device_type': type_map.get(vendor_type, 'huawei'), 'host': device['ip'], 'username': device['username'], 'password': device['password'], } try: with ConnectHandler(**conn_params) as conn: output = conn.send_command(cmd, read_timeout=30) return parse_ospf_peers(output, vendor_type) except Exception as e: print(f”[{device['name']}] 连接失败: {e}”) return Nonedef parse_ospf_peers(output, vendor_type): peers = {} if vendor_type in ('huawei', 'h3c'): lines = output.strip().split('\n') for line in lines: parts = line.split() if len(parts) >= 4 and re.match(r'\d+\.\d+\.\d+\.\d+', parts[0]): peer_ip = parts[0] state = parts[-1] peers[peer_ip] = state elif vendor_type == 'ruijie': lines = output.strip().split('\n') for line in lines: parts = line.split() if len(parts) >= 3 and re.match(r'\d+\.\d+\.\d+\.\d+', parts[0]): peer_ip = parts[0] state = parts[2].split('/')[0] peers[peer_ip] = state return peersdef check_and_alert(devices): alerts = [] for dev in devices: current_peers = get_ospf_neighbors(dev) if current_peers is None: alerts.append(f”{dev['name']}({dev['ip']}): SSH连接失败,无法采集”) continue for peer_ip, state in current_peers.items(): if state != 'Full': alerts.append( f”{dev['name']}({dev['ip']}): 邻居 {peer_ip} 状态={state}” ) if len(current_peers) == 0: alerts.append(f”{dev['name']}({dev['ip']}): 无OSPF邻居,请检查配置”) if alerts: send_alert(alerts)def send_alert(alerts): body = ”\n”.join(alerts) msg = MIMEText(body, 'plain', 'utf-8') msg['Subject'] = f'OSPF邻居状态告警 {time.strftime(”%Y-%m-%d %H:%M”)}' msg['From'] = 'monitor@local' msg['To'] = 'ops@local' with smtplib.SMTP('smtp.local', 25) as s: s.send_message(msg) print(f”已发送告警邮件,共{len(alerts)}条”)if __name__ == '__main__': devices = load_devices('devices.yaml') check_and_alert(devices)
脚本逻辑说明几点。OSPF邻居状态正常应该是Full,出现Init、ExStart、Exchange、Loading都说明邻居建立有问题,需要关注。如果一台设备完全没有邻居信息返回,可能是OSPF进程没启动或者所有接口down了,这种情况比单个邻居异常更严重。
华为和华三的输出格式基本一致,锐捷用show命令格式不同,解析逻辑要分开处理。实际部署时建议先手动执行一次display命令看输出格式,确认解析正则匹配没问题再放到定时任务里跑。
定时执行用Linux的crontab,每5分钟跑一次:
*/5 * * * * /usr/bin/python3 /opt/scripts/ospf_monitor.py >> /var/log/ospf_monitor.log 2>&1
Windows环境用任务计划程序,设触发器为每5分钟执行。脚本输出重定向到日志文件,方便事后回溯。
有个细节容易踩坑。netmiko连华为设备时,如果命令输出超过一屏会有分页提示" ---- More ----",netmiko的send_command方法默认会自动处理分页,但有些固件版本的分页符不一样,可能导致输出截断。可以在连接参数里加global_delay_factor = 2放慢节奏,或者提前在设备上取消分页:screen-length 0 temporary(华为)或screen-length disable(华三)。