设备配置变更管理是运维的基本功。以前每次变更后手动备份配置,然后肉眼对比新旧版本找差异,10台设备还能应付,几十台设备就力不从心了。漏看一条配置变更可能导致故障排查时走弯路。
后来用Python写了个配置比对脚本,自动拉取设备当前配置和上次备份对比,高亮差异行,生成变更报告。配合定时任务每天跑一次,设备配置有任何变更第二天就能发现。
脚本用netmiko拉取配置,用difflib做文本比对。netmiko支持主流网络设备,华为、华三、锐捷、迈普都有对应的device type。difflib是Python标准库,不需要额外安装。
import osfrom datetime import datetimefrom netmiko import ConnectHandlerimport difflib# 设备清单devices = [ {'host': '192.168.1.1', 'username': 'admin', 'password': 'pwd', 'device_type': 'huawei'}, {'host': '192.168.1.2', 'username': 'admin', 'password': 'pwd', 'device_type': 'hp_comware'},]BACKUP_DIR = './backups'DIFF_DIR = './diffs'def get_running_config(dev): with ConnectHandler(**dev) as conn: output = conn.send_command('display current-configuration') return outputdef save_config(ip, config): os.makedirs(BACKUP_DIR, exist_ok=True) filename = f'{BACKUP_DIR}/{ip}_{datetime.now().strftime(”%Y%m%d”)}.cfg' with open(filename, 'w', encoding='utf-8') as f: f.write(config) return filenamedef get_last_backup(ip): files = [f for f in os.listdir(BACKUP_DIR) if f.startswith(ip)] if not files: return None files.sort(reverse=True) if len(files) == 1: return None# 只有今天的,没有上次的 last_file = files[1]# 倒数第二个是上次备份 with open(f'{BACKUP_DIR}/{last_file}', 'r', encoding='utf-8') as f: return f.read()def compare_config(ip, current, last): if last is None: return '首次备份,无对比基线' current_lines = current.splitlines() last_lines = last.splitlines() diff = difflib.unified_diff(last_lines, current_lines, fromfile='last_backup', tofile='current', lineterm='') diff_text = '\n'.join(diff) return diff_text if diff_text else '无变更'if __name__ == '__main__': os.makedirs(DIFF_DIR, exist_ok=True) for dev in devices: ip = dev['host'] try: config = get_running_config(dev) save_config(ip, config) last = get_last_backup(ip) diff = compare_config(ip, config, last) report = f'设备: {ip}\n时间: {datetime.now()}\n差异:\n{diff}\n' diff_file = f'{DIFF_DIR}/{ip}_{datetime.now().strftime(”%Y%m%d”)}.txt' with open(diff_file, 'w', encoding='utf-8') as f: f.write(report) print(f'{ip}: {diff[:100] if diff != ”无变更” else ”无变更”}') except Exception as e: print(f'{ip}: 采集失败 - {e}')
脚本逻辑分三步:拉取当前配置并保存,找到上一次备份,用difflib生成unified diff格式的差异报告。首次运行时没有历史备份,会提示"首次备份,无对比基线",从第二次运行开始才有对比结果。
有个实际使用中的坑要注意。华为设备的display current-configuration输出中,有些行包含时间戳信息,比如"! Last configuration changed at 2026-07-04 14:00:00"这种。每次配置没变但时间戳变了,diff就会报差异。解决方法是在比对前过滤掉这些行:
def filter_config(config): skip_patterns = ['#', '!', 'Last configuration', 'clock'] lines = [l for l in config.splitlines() if not any(p in l for p in skip_patterns)] return '\n'.join(lines)
华三的display current-configuration也有类似问题,输出里有些注释行和时间信息需要过滤。锐捷的show running-config格式相对干净,但也有版本号等信息需要处理。多厂商环境下,每家的输出都要单独做清洗。
netmiko针对不同厂商需要指定不同的device_type,配错了连接会失败。下面是国内常见厂商对应的device_type:
脚本里建议把device_type写到设备清单的配置文件中,每台设备单独指定,避免硬编码。我们用的是Excel清单转CSV,包含IP、用户名、密码、device_type、拉配置命令几列,新增设备只改清单不改代码。
另一个改进点是把diff结果推送到企业微信或钉钉。脚本里加个webhook发送函数,发现配置变更自动通知,不用人工去翻diff文件。我们现在的流程是每天凌晨2点定时跑脚本,7点把变更汇总推送到运维群,上班就能看到昨晚哪些设备配置变了。
配置比对除了发现意外变更,还能辅助故障排查。设备出故障时先跑一次比对,看看最近有没有配置变更,很多时候故障就是某个不当的配置变更引起的。这个习惯帮我快速定位过好几次问题,比翻日志高效。