1.背景介绍
因日常运维需求需要收集配置和接口信息,用于配置备份和审计要求,以及机房搬迁、数据治理等原因需要配置信息收集; 配置采集需每天都要处理,且登陆网络设备的操作命令基本一致,且重复操作次数明显超过3次,考虑对接标准化和自动化操作; 标准化:不同品牌、不同类型的设备进行分组分类,按类别整理出标准化流程后,开始对其自动化;
2.模拟环境
本次模拟环境是华为模拟器ENSP,设备是CE6800(请注意,配置命令后要commit生效),IP地址已标注在图上; 拓扑如下图所示:
2.1 配置接口IP地址
在CE1-CE3配置接口IP地址,以CE1为例子 interface GE1/0/0 undo portswitch undo shutdown ip address 192.168.58.202 255.255.255.0 生产环境中,需要敬畏之心,再小的操作(变更操作),均要验证,输出的命令是否符合预期; CE1-CE3配置完成后,在CE1进行ping测试,可以验证出互通性和配置是否正确以及是否产生意料之外的问题(生产环境会有奇奇怪怪的问题,软件或硬件都可能会出现bug);
2.2 配置SSH登陆
2.2.1 配置VTY用户界面
user-interface vty 0 4 authentication-mode aaa protocol inbound ssh
2.2.2 配置AAA认证
用户名和密码需要记录好,模拟环境使用弱口令密码,实际请使用复杂密码; aaa local-user admin@123 password irreversible-cipher 123456789 local-user admin@123 service-type ssh local-user admin@123 level 3 华为交换机基于安全考虑,默认开启本地账户安全策略功能,用户第一次登录时会被要求更改密码。 如果配置了下次登录提醒修改原始密码功能,用户登录也会提醒更改密码,实际使用过程比较麻烦,可以按需取消第一次登录更改密码的询问。 【题外话:安全是平衡的艺术,业务盈利、运维效率、数据安全三者求平衡】 undo local-user policy security-enhance undo local-user policy password change
2.2.3 配置SSH用户
stelnet server enable ssh user admin@123 ssh user admin@123 authentication-type password ssh user admin@123 service-type all ssh authorization-type default aaa
2.2.4 配置SSH登陆验证
做变更要严格按照SOP执行,一定要做变更验证,变更做完不是结束,验证完成才算。
3.批量登陆脚本
3.1 设备清单表样式
模拟环境仅作演示,密码记录表格,实际情况是禁止在本地保存明文用户和密码;
3.2 脚本逻辑
1)读取设备清单表,获取表头信息和每一行数据,将表头作为键,行数据作为值形成字典,见示例1;每个字典添加到列表中,见示例2; 示例1:{'设备登陆IP': '192.168.58.200'} 示例2:[{'设备登陆IP': '192.168.58.200'}, {'设备登陆IP': '192.168.58.201'}] 2)根据获取的登陆信息,登陆每台设备;成功和失败没有写入文件,只在程序页面打印,后续优化为输出记录文件; 3)执行输入的命令获取设备输出信息,直接打印获取信息,后续可以写入文件进行持久化保存;
3.3 脚本代码清单
import time
import openpyxl
import paramiko
def read_excel(file_path):
'''
读取设备清单表,将读取的表头和行数据组合成字典,字典组合成列表数据
'''
# 加载Excel文件并获取活动的sheet
wb = openpyxl.load_workbook(file_path)
sheet = wb.active
data = []
# 获取表头数据
headers = [cell.value for cell in sheet[1]]
# 遍历每一行数据,表头和行数据创建字典,
for row in sheet.iter_rows(min_row=2, values_only=True):
device_info = {}
for header, value in zip(headers, row):
device_info[header] = value
# 将字典添加到数据列表中
data.append(device_info)
print('表格格式化数据,验证表格数据取数是否正常', data)
return data
def ssh_connect(ip, username, password):
'''创建 SSH 客户端对象,并设置自动添加主机密钥的策略'''
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(ip, username=username, password=password)
return client
def execute_commands(client, commands):
'''命令执行函数,遍历命令发送到交互式窗口,并收集输出'''
outputs = []
client = client.invoke_shell()
for command in commands:
client.send(command + "\n") # 发送命令并换行
time.sleep(1) # 等待1秒,保证接收数据的完整性
output = client.recv(65535).decode('utf-8')
outputs.append(output) # 命令执行结果添加到输出列表中
client.close()
return outputs
def main():
'''输入设备清单表的位置,'''
excel_file = "D:\TESTCORE\设备清单表.xlsx"
devices = read_excel(excel_file)
for device in devices:
ip = device.get("设备登陆IP")
username = device.get("设备登陆用户")
password = device.get("设备登陆密码")
commands = [
device.get("设备输入命令1"),
device.get("设备输入命令2"),
device.get("设备输入命令3")
]
try:
client = ssh_connect(ip, username, password)
outputs = execute_commands(client, commands)
print(f"设备{ip}的命令输出结果:")
for output in outputs:
print(output)
except Exception as e:
print(f"连接错误 {ip}: {str(e)}")
if __name__ == "__main__":
main()
3.4 脚本运行效果
运行正常的截图 修改设备清单表,设置密码为错误密码,运行截图如下: 修改设备清单表,设置一个不存在的IP地址,运行截图如下: 有时候知道错误原因比只知其然,而不知其所以然的成功更要紧。