写在前面的话:
上次完成CE巡检模块后,老大要求从堡垒机上进行跳转,实现输入堡垒机上自己的个人账号和密码即可巡检。
实验目的:
完成华为CE系列,S系列(S6700或S9300),锐捷S系列巡检,巡检完成后输出Excel做出统计信息。
前期环境配置
import getpass
import paramiko
import time
import requests
import re
import openpyxl
import atexit
import pandas as pd
import urllib3
import json
主函数及异常处理
result_data = []
def main():
username = input("请输入堡垒机登录用户名:")
password = getpass.getpass("请输入堡垒机登录密码:")
# 登录堡垒机
client = login_to_jump_server(username, password)
if not client:
return
print('\n' * 2 + "恭喜,堡垒机登录成功!" + '\n' * 2 )
# 获取Token数据
token_data = get_token()
if not token_data:
return
print('\n' * 2 + "获取Token信息成功!" + '\n' * 2 )
# 存储结果数据
global result_data
result_data = []
try:
for item in token_data:
hostname = item[0]
port = item[1]
ip = item[2]
# 添加调试输出
print("处理设备:", hostname)
# 判断关键字,执行对应逻辑
device_type = None
for keyword in ['CE', 'FM', 'S6720', 'S93', 'S6250']:
if keyword in hostname:
device_type = keyword
break
if device_type in ['CE', 'FM']:
device_data = C_F_function(client, hostname, ip, port)
elif device_type == 'S6720':
device_data = S6720_function(client, hostname, ip, port)
elif device_type == 'S93':
device_data = S9303_9306_9312_function(client, hostname, ip, port)
elif device_type == 'S6250':
device_data = Ruijie_S6250_function(client, hostname, ip, port)
else:
device_data = Few_unknown_function(client, hostname)
# 添加调试输出
print("设备数据:", device_data)
# 存储结果数据
result_data.append([hostname, ip, device_data['software_version'], device_data['cpu_utilization'],
device_data['memory_utilization'], device_data['total_power'], device_data['active_power'],
device_data['normal_power'], device_data['total_fans'], device_data['active_fans'],
device_data['normal_fans'], device_data['temperature_status']])
except Exception as e:
print("发生异常:", str(e))
# 保存已巡检的内容到Excel文件
write_to_excel(result_data)
return
# 将结果写入Excel
write_to_excel(result_data)
# 关闭SSH连接
client.close()
# 定义程序关闭时的处理函数
def exit_handler():
# 保存已巡检的内容到Excel文件
write_to_excel(result_data)
if __name__ == "__main__":
# 注册程序关闭时的处理函数
atexit.register(exit_handler)
main()
登录堡垒机模块
def login_to_jump_server(username, password):
# 创建一个SSH客户端对象
client = paramiko.SSHClient()
try:
# 设置自动添加主机密钥
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接到堡垒机
client.connect('IP/域名', port=端口号, username=username, password=password)
# 返回SSH客户端对象
return client
except paramiko.AuthenticationException:
# 登录失败
print("登录失败!用户名或密码错误。")
return None
except paramiko.SSHException as ssh_exception:
# SSH连接异常
print("SSH连接失败:", str(ssh_exception))
return None
通过API获取Token
def get_token():
headers = {
'AccessToken': 'API访问键',
'Content-Type': 'application/json'
}
# 创建一个不验证证书的 PoolManager 对象
http = urllib3.PoolManager(cert_reqs='CERT_NONE')
# 发起 HTTPS 请求
response = http.request('GET', 'https://IP/api/operations', headers=headers)
if response.status == 200:
# 解析返回的数据
token = json.loads(response.data.decode('utf-8'))
operation_lists = token.get('operationLists', [])
# 解析返回的数据并返回
extracted_data = []
for operation in operation_lists:
# 提取所需信息
host_name = operation.get('hostName', '')
port = operation.get('accounts', [{}])[0].get('port', '')
host_ip = operation.get('hostIp', '')
extracted_data.append([host_name, port, host_ip])
return extracted_data
else:
print("无法检索到Token。状态代码:", response.status)
return []
这里需要注意到通过API获取Token,可以参考堡垒机对应品牌给出的示例
CE与FM系列交换机巡检模块
def C_F_function(ssh_client, hostname, ip, port):
try:
shell = ssh_client.invoke_shell()
shell.send(f'ssh -l jumper {ip} -p {port}\n')
time.sleep(6)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
# 进入设备
time.sleep(2)
shell.send('n' + '\n' * 2)
time.sleep(1)
# 获取版本信息
command = 'display version | no-more\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
# 使用正则表达式匹配所需信息
software_version = re.search(r'VRP \(R\) software, Version .+? \((.+?)\)', output)
software_version = software_version.group(1) if software_version else ""
print("版本信息:", software_version)
# 获取CPU利用率信息
command = 'display cpu | no-more\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
cpu_utilization = re.search(r'System CPU Using Percentage : +(\d+)%', output)
cpu_utilization = f"{cpu_utilization.group(1)}%" if cpu_utilization else 0.0
print("CPU利用率:", cpu_utilization)
# 获取内存利用率信息
command = 'display memory | no-more\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
memory_utilization = re.search(r'Memory Using Percentage: (\d+)%', output)
memory_utilization = f"{memory_utilization.group(1)}%" if memory_utilization else 0.0
print("内存利用率:", memory_utilization)
# 获取电源信息
command = 'display device power | no-more\n'
shell.send(command)
time.sleep(3.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
power_lines = output.split('\n')
total_power = 0
active_power = 0
normal_power = 0
for line in power_lines:
if 'N/A:Power not available' in line:
break
if 'PWR' in line:
total_power += 1
if re.search(r'YES', line, re.IGNORECASE):
active_power += 1
if re.search(r'Supply', line, re.IGNORECASE):
normal_power += 1
print("总电源数:", total_power)
print("使用电源数:", active_power)
print("正常电源数:", normal_power)
# 获取风扇信息
command = 'display device fan | no-more\n'
shell.send(command)
time.sleep(3.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
fan_lines = output.split('\n')
total_fans = 0
active_fans = 0
normal_fans = 0
for line in fan_lines:
if 'N/A:Fan not available' in line:
break
if 'FAN' in line:
total_fans += 1
speed_match = re.search(r'\d+%', line)
if speed_match:
speed = int(speed_match.group().strip('%'))
if speed > 5:
active_fans += 1
if 'Normal' in line:
normal_fans += 1
print("总风扇数:", total_fans)
print("使用风扇数:", active_fans)
print("正常风扇数:", normal_fans)
# 获取温度信息
command = 'display device temperature all | no-more\n'
shell.send(command)
time.sleep(3)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
if 'Error: Too many parameters found at ' in output:
# 备用命令
command = 'display device temperature | no-more\n'
shell.send(command)
time.sleep(3)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
temperature_lines = output.split('\n')
temperature_data = []
for line in temperature_lines:
line_data = line.strip().split() # 将行数据按空格分割成列表
if len(line_data) == 8:
temperature_data.append(line_data) # 将符合条件的行数据加入温度数据列表
temperature_status = "Normal"
for data in temperature_data:
if data[3].upper() != "NORMAL":
temperature_status = "Abnormal" # 如果有任何温度状态不是"Normal",将温度状态设为"Abnormal"
break
print("温度状态:", temperature_status)
# 退出网络设备
shell.send('quit\n')
time.sleep(1)
return {
'hostname': hostname,
'software_version': software_version,
'cpu_utilization': cpu_utilization,
'memory_utilization': memory_utilization,
'total_power': total_power,
'active_power': active_power,
'normal_power': normal_power,
'total_fans': total_fans,
'active_fans': active_fans,
'normal_fans': normal_fans,
'temperature_status': temperature_status
}
except paramiko.ssh_exception.SSHException as e:
import traceback
print(f"在处理CE或FM设备时发生异常: {repr(e)}")
traceback.print_exc()
return {
'hostname': hostname,
'software_version': '',
'cpu_utilization': 0.0,
'memory_utilization': 0.0,
'total_power': 0,
'active_power': 0,
'normal_power': 0,
'total_fans': 0,
'active_fans': 0,
'normal_fans': 0,
'temperature_status': 'Unknown'
}
S6720巡检模块
def S6720_function(ssh_client, hostname, ip, port):
try:
shell = ssh_client.invoke_shell()
shell.send(f'ssh -l jumper {ip} -p {port}\n')
time.sleep(6)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
# 进入设备
time.sleep(2)
shell.send('n' + '\n' * 2)
time.sleep(1)
# 获取版本信息
command = 'display version\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A\n') # 发送Ctrl+Z并换行
time.sleep(1)
software_version = re.search(r'VRP \(R\) software, Version .+? \((.+?)\)', output)
software_version = software_version.group(1) if software_version else ""
print("软件版本:", software_version)
# 获取CPU利用率信息
command = 'display cpu-usage\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A') # 发送Ctrl+Z并换行
time.sleep(1)
cpu_utilization = re.search(r'CPU Usage : +(\d+)%', output)
cpu_utilization = f"{cpu_utilization.group(1)}%" if cpu_utilization else "0.0%"
print("CPU利用率:", cpu_utilization)
# 获取内存利用率信息
command = 'display memory-usage\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A\n') # 发送Ctrl+Z并换行
time.sleep(1)
memory_utilization = re.search(r'Memory Using Percentage Is: (\d+)%', output)
memory_utilization = f"{memory_utilization.group(1)}%" if memory_utilization else "0.0%"
print("内存利用率:", memory_utilization)
# 获取电源信息
command = 'display device\n'
shell.send(command)
time.sleep(3.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
power_lines = output.split('\n')
total_power = 0
active_power = 0
normal_power = 0
for line in power_lines:
if 'PWR' in line:
total_power += 1
if re.search(r'Present', line, re.IGNORECASE):
active_power += 1
if re.search(r'Normal', line, re.IGNORECASE):
normal_power += 1
print("总电源数:", total_power)
print("使用电源数:", active_power)
print("正常电源数:", normal_power)
# 获取风扇信息
command = 'display fan\n'
shell.send(command)
time.sleep(3.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
fan_lines = output.split('\n')
total_fans = 0
active_fans = 0
normal_fans = 0
for line in fan_lines:
fan_match = re.match(r'\s*\d+\s+', line) # 匹配以数字开头的行
if fan_match:
total_fans += 1
if 'Present' in line: # 匹配包含Present的行
active_fans += 1
if 'Normal' in line: # 匹配包含Normal的行
normal_fans += 1
print("总风扇数:", total_fans)
print("使用风扇数:", active_fans)
print("正常风扇数:", normal_fans)
# 获取温度信息
command = 'display temperature all\n'
shell.send(command)
time.sleep(3)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
temperature_lines = output.split('\n')
temperature_data = []
for line in temperature_lines:
line_data = line.strip().split()
if len(line_data) == 8:
temperature_data.append(line_data)
temperature_status = "Normal"
for data in temperature_data:
if data[3].upper() != "NORMAL":
temperature_status = "Abnormal"
break
print("温度状态:", temperature_status)
# 退出设备
shell.send('quit\n')
time.sleep(1)
return {
'hostname': hostname,
'software_version': software_version,
'cpu_utilization': cpu_utilization,
'memory_utilization': memory_utilization,
'total_power': total_power,
'active_power': active_power,
'normal_power': normal_power,
'total_fans': total_fans,
'active_fans': active_fans,
'normal_fans': normal_fans,
'temperature_status': temperature_status
}
except paramiko.ssh_exception.SSHException as e:
import traceback
print(f"在处理CE设备时发生异常: {repr(e)}")
traceback.print_exc()
return {
'hostname': hostname,
'software_version': '',
'cpu_utilization': '0.0%',
'memory_utilization': '0.0%',
'total_power': 0,
'active_power': 0,
'normal_power': 0,
'total_fans': 0,
'active_fans': 0,
'normal_fans': 0,
'temperature_status': 'Unknown'
}
S9300系列巡检模块
def S9303_9306_9312_function(ssh_client, hostname, ip, port):
try:
shell = ssh_client.invoke_shell()
shell.send(f'ssh -l jumper {ip} -p {port}\n')
time.sleep(6)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
# 进入设备
time.sleep(2)
shell.send('n' + '\n' * 2)
time.sleep(1)
# 获取版本信息
command = 'display version\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A\n') # 发送Ctrl+Z并换行
time.sleep(1)
# 使用正则表达式匹配所需信息
software_version = re.search(r'VRP \(R\) software, Version .+? \((.+?)\)', output)
software_version = software_version.group(1) if software_version else ""
print("软件版本:", software_version)
# 获取CPU利用率信息
command = 'display cpu-usage\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A\n') # 发送Ctrl+Z并换行
time.sleep(1)
cpu_utilization = re.search(r'CPU Usage : +(\d+)%', output)
cpu_utilization = f"{cpu_utilization.group(1)}%" if cpu_utilization else "0.0%"
print("CPU利用率:", cpu_utilization)
# 获取内存利用率信息
command = 'display memory-usage\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A\n') # 发送Ctrl+Z并换行
time.sleep(1)
memory_utilization = re.search(r'Memory Using Percentage Is: (\d+)%', output)
memory_utilization = f"{memory_utilization.group(1)}%" if memory_utilization else "0.0%"
print("内存利用率:", memory_utilization)
# 获取电源信息
command = 'display device\n'
shell.send(command)
time.sleep(3.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
power_lines = output.split('\n')
total_power = 0
active_power = 0
normal_power = 0
for line in power_lines:
if 'PWR' in line:
total_power += 1
if re.search(r'Present', line, re.IGNORECASE):
active_power += 1
if re.search(r'Normal', line, re.IGNORECASE):
normal_power += 1
print("总电源数:", total_power)
print("使用电源数:", active_power)
print("正常电源数:", normal_power)
# 获取风扇信息
command = 'display fan\n'
shell.send(command)
time.sleep(3.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
fan_lines = output.split('\n')
total_fans = 0
active_fans = 0
normal_fans = 0
for line in fan_lines:
if 'FAN' in line: # 匹配包含FAN的行
total_fans += 1
if 'AUTO' in line.upper(): # 匹配包含AUTO(不区分大小写)的行
active_fans += 1
speed_match = re.search(r'(\d+)%', line) # 匹配百分比数字
if speed_match:
speed = int(speed_match.group(1))
if speed < 75:
normal_fans += 1
print("总风扇数:", total_fans)
print("使用风扇数:", active_fans)
print("正常风扇数:", normal_fans)
# 获取温度信息
command = 'display temperature all\n'
shell.send(command)
time.sleep(3)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
lines = output.split('\n')
temperature_status = "Abnormal" # 默认温度状态为异常
for line in lines:
if re.search(r'Normal', line, re.IGNORECASE):
temperature_status = "Normal"
break
print("温度状态:", temperature_status)
# 退出设备
shell.send('quit\n')
time.sleep(1)
return {
'hostname': hostname,
'software_version': software_version,
'cpu_utilization': cpu_utilization,
'memory_utilization': memory_utilization,
'total_power': total_power,
'active_power': active_power,
'normal_power': normal_power,
'total_fans': total_fans,
'active_fans': active_fans,
'normal_fans': normal_fans,
'temperature_status': temperature_status
}
except paramiko.ssh_exception.SSHException as e:
import traceback
print(f"在处理CE设备时发生异常: {repr(e)}")
traceback.print_exc()
return {
'hostname': hostname,
'software_version': '',
'cpu_utilization': '0.0%',
'memory_utilization': '0.0%',
'total_power': 0,
'active_power': 0,
'normal_power': 0,
'total_fans': 0,
'active_fans': 0,
'normal_fans': 0,
'temperature_status': 'Unknown'
}
锐捷巡检模块
def Ruijie_S6250_function(ssh_client, hostname, ip, port):
try:
shell = ssh_client.invoke_shell()
shell.send(f'ssh -l jumper {ip} -p {port}\n')
time.sleep(6)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
# 进入CE设备
time.sleep(2)
shell.send('n\n' + '\n' * 2)
time.sleep(1)
# 获取版本信息
command = 'show version\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A') # 发送Ctrl+Z
time.sleep(1)
# 使用正则表达式匹配所需信息
software_version = re.search(r'System software version\s+:\s+(.*?)\n', output)
software_version = software_version.group(1) if software_version else ""
print("版本号:", software_version)
# 获取CPU利用率信息
command = 'show cpu\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A') # 发送Ctrl+Z
time.sleep(1)
cpu_utilization = re.search(r'CPU utilization in one minute:\s+(\d+\.\d+)%', output)
cpu_utilization = f"{cpu_utilization.group(1)}%" if cpu_utilization else 0.0
print("CPU利用率:", cpu_utilization)
# 获取内存利用率信息
command = 'show memory\n'
shell.send(command)
time.sleep(1.5)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
shell.send('\x1A') # 发送Ctrl+Z
time.sleep(1)
memory_utilization = re.search(r'System Memory: .+?(\d+\.\d+)% used rate', output)
memory_utilization = f"{memory_utilization.group(1)}%" if memory_utilization else 0.0
print("内存利用率:", memory_utilization)
# 获取电源信息
command = 'show power\n'
shell.send(command)
time.sleep(2)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
power_lines = output.split('\n')
total_power = 0
active_power = 0
normal_power = 0
for line in power_lines:
if 'N/A' in line: # 匹配包含N/A的行
total_power += 1
if re.search(r'YES', line, re.IGNORECASE): # 匹配包含YES的行(不区分大小写)
active_power += 1
if re.search(r'OK', line, re.IGNORECASE): # 匹配包含OK的行(不区分大小写)
normal_power += 1
print("总电源数:", total_power)
print("使用电源数:", active_power)
print("正常电源数:", normal_power)
# 获取风扇信息
command = 'show fan\n'
shell.send(command)
time.sleep(2)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
fan_lines = output.split('\n')
total_fans = 0
active_fans = 0
normal_fans = 0
for line in fan_lines:
if re.match(r'\d+', line): # 匹配以数字开头的行
total_fans += 1
if 'M1EFAN' in line: # 匹配包含M1EFAN的行
active_fans += 1
if re.search(r'OK', line, re.IGNORECASE): # 匹配包含OK的行(不区分大小写)
normal_fans += 1
print("总风扇数:", total_fans)
print("使用风扇数:", active_fans)
print("正常风扇数:", normal_fans)
# 获取温度信息
command = 'show temperature\n'
shell.send(command)
time.sleep(2)
output = ''
while shell.recv_ready():
output += shell.recv(1024).decode()
lines = output.split('\n')
ok_count = sum(1 for line in lines if re.search(r'OK', line, re.IGNORECASE))
if ok_count >= 5 or ok_count >= 10:
temperature_status = "Normal"
else:
temperature_status = "Abnormal"
print("温度状态:", temperature_status)
# 退出设备
shell.send('exit\n')
time.sleep(1)
return {
'hostname': hostname,
'software_version': software_version,
'cpu_utilization': cpu_utilization,
'memory_utilization': memory_utilization,
'total_power': total_power,
'active_power': active_power,
'normal_power': normal_power,
'total_fans': total_fans,
'active_fans': active_fans,
'normal_fans': normal_fans,
'temperature_status': temperature_status
}
except paramiko.ssh_exception.SSHException as e:
import traceback
print(f"在处理CE设备时发生异常: {repr(e)}")
traceback.print_exc()
return {
'hostname': hostname,
'software_version': '',
'cpu_utilization': 0.0,
'memory_utilization': 0.0,
'total_power': 0,
'active_power': 0,
'normal_power': 0,
'total_fans': 0,
'active_fans': 0,
'normal_fans': 0,
'temperature_status': 'Unknown'
}
少量未知模块巡检
def Few_unknown_function(ssh_client, hostname):
return {
'hostname': hostname,
'software_version': 0,
'cpu_utilization': 0,
'memory_utilization': 0,
'total_power': 0,
'active_power': 0,
'normal_power': 0,
'total_fans': 0,
'active_fans': 0,
'normal_fans': 0,
'temperature_status': 0
}
写入Excel模块
def write_to_excel(data):
# 创建一个新的Excel工作簿
wb = openpyxl.Workbook()
# 选择或创建一个工作表
sheet = wb.active
# 写入表头
sheet.append(["交换机名称", "IP", "软件版本", "CPU利用率", "内存利用率", "总电源", "使用电源", "正常电源", "总风扇", "使用风扇", "正常风扇", "温度状态"])
# 将数据写入Excel文件
for d in data:
sheet.append(d)
# 保存Excel文件
wb.save('network_data.xlsx')
# 创建DataFrame对象
df = pd.DataFrame(data, columns=["交换机名称", "IP", "软件版本", "CPU利用率", "内存利用率", "总电源", "使用电源", "正常电源", "总风扇", "使用风扇", "正常风扇", "温度状态"])
# 打印输出到控制台
print("以下是巡检结果:")
print(df)
这里分享一个设计图标的小网站:
LOGO设计神器;公司logo在线设计生成器 - 标小智LOGO神器 (logosc.cn)
可以先自己设计一个小图标,然后根据下面这个免费转换成.ico格式的图片
ConvertICO.com - Convert PNG to ICO, quickly
根据自己设计的图片将Python文件打包,代码如下:
pyinstaller --onefile --icon=文件名.ico 文件名.py
pyinstaller 文件名.spec
测试如下:
结论
终于写完这屎山一样的代码了!!!