业务需求:
1)监测IP不通时,将Cacti流量图发出来
2)流量超设定阈值时,将Cacti流量图发出来
从cacti上查看graph_id

配置文件:
{
"client_info": {
"1": {
"name": "User1",
"ip": "192.168.1.1",
"bandwidth": 500,
"graph_id" : 561,
"threshold": 10
},
"2": {
"name": "User2",
"ip": "192.168.1.2",
"bandwidth": 220,
"graph_id" : 596,
"threshold": 0
}
}
def Combine_Images_Vertically(images_list=[], output_path_filename=None):
images = [Image.open(image) for image in images_list]
widths, heights = zip(*(i.size for i in images))
new_width = max(widths)
new_height = sum(heights)
new_image = Image.new('RGB', (new_width, new_height))
y_offset = 0
for img in images:
new_image.paste(img, (0, y_offset))
y_offset += img.height
new_image.save(output_path_filename)
if os.path.exists(output_path_filename):
return True
else:
return False
def Ping_IP(ip):
try:
for _ in range(5):
output = subprocess.run(['ping', '-c', '1', ip], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True, timeout=5)
if output.returncode == 0:
return (ip, "alive")
return (ip, "dead")
except subprocess.TimeoutExpired:
return (ip, "timeout")
except Exception as e:
return (ip, "error")
def Check_CrossLine_HK_VM(ip_list):
results = []
with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:
for result in executor.map(Ping_IP, ip_list):
results.append(result)
return results
def Delete_Old_Cacti_Files(graph_id, minutes_old=30):
prefix1 = f"cacti_graph_{graph_id}_past_one_day_"
prefix2 = f"cacti_graph_{graph_id}_past_half_hour_"
prefix3 = f"cacti_graph_{graph_id}_combine_"
prefix4 = f"cacti_graph_{graph_id}_past_week_"
prefixes = [prefix1, prefix2, prefix3, prefix4]
now = datetime.now()
old_time = now - timedelta(minutes=minutes_old)
old_time_prefix3 = now - timedelta(days=1)
file_types = ['csv', 'png', 'svg']
for prefix in prefixes:
for file_type in file_types:
file_pattern = os.path.join(IMG_WEB_DIR, f"{prefix}*.{file_type}")
for file_path in glob(file_pattern):
try:
file_name = os.path.basename(file_path)
timestamp_str = file_name.split(prefix)[1].split(f'.{file_type}')[0]
file_timestamp = int(timestamp_str)
file_mod_time = datetime.fromtimestamp(file_timestamp)
if prefix == prefix3:
if file_mod_time <= old_time_prefix3:
os.remove(file_path)
running_logger.info(f"Deleted file: {file_path}")
else:
if file_mod_time <= old_time:
os.remove(file_path)
running_logger.info(f"Deleted file: {file_path}")
except Exception as e:
print(f"Error deleting file {file_path}: {e}")
def Monitor_Cacti_Traffic(erp=None,group_id=None):
ip_list = []
session = requests.session()
header = {
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36",
}
def tobit(value):
if not isinstance(value, (int, float)):
return '0b'
for unit in ['b', 'K', 'M', 'G', 'T']:
if value < 1000.0:
return f"{value:.1f}{unit}"
value /= 1000.0
return f"{value:.1f}T"
def Send_Image(graph_id, graph_name_descr, user_bandwidth, alarm_threshold, vip_check=False):
try:
res1 = session.get(Cacti_LOGIN_URL, headers=header).text
c_token = re.findall('var csrfMagicToken = "(.*?)";', res1)[0]
data = {
"__csrf_magic": c_token,
"action": "login",
"login_username": Cacti_LOGIN_USER,
"login_password": Cacti_LOGIN_PWD,
}
request1 = session.post(url=Cacti_LOGIN_URL, data=data, headers=header)
if request1.status_code == 200:
now = int(time.time())
past_hour = now - 3600
past_day = now - 86400
image_url_past_hour = f"{Cacti_LOGIN_URL}/graph_image.php?local_graph_id={graph_id}&rra_id=0&graph_height=300&graph_width=1000&title_font_size=10&view_type=tree&graph_start={past_hour}&graph_end={now}"
image_url_past_day = f"{Cacti_LOGIN_URL}/graph_image.php?local_graph_id={graph_id}&rra_id=0&graph_height=300&graph_width=1000&title_font_size=10&view_type=tree&graph_start={past_day}&graph_end={now}"
request = session.get(url=image_url_past_hour, headers=header, timeout=10)
aw1 = request.content
_past_half_hour_save_path_svg = os.path.join(IMG_WEB_DIR, f"cacti_graph_{graph_id}_past_half_hour_{now}.svg")
_past_half_hour_save_path_png = os.path.join(IMG_WEB_DIR, f"cacti_graph_{graph_id}_past_half_hour_{now}.png")
with open(_past_half_hour_save_path_svg, 'wb') as file:
file.write(aw1)
cairosvg.svg2png(url=_past_half_hour_save_path_svg,write_to=_past_half_hour_save_path_png)
request = session.get(url=image_url_past_day, headers=header, timeout=10)
aw2 = request.content
_past_one_day_save_path_svg = os.path.join(IMG_WEB_DIR, f"cacti_graph_{graph_id}_past_one_day_{now}.svg")
_past_one_day_save_path_png = os.path.join(IMG_WEB_DIR, f"cacti_graph_{graph_id}_past_one_day_{now}.png")
with open(_past_one_day_save_path_svg, 'wb') as file:
file.write(aw2)
cairosvg.svg2png(url=_past_one_day_save_path_svg,write_to=_past_one_day_save_path_png)
rendered_images_fullpath_list = [_past_half_hour_save_path_png, _past_one_day_save_path_png]
image_file_name_combine = f"cacti_graph_{graph_id}_combine_{now}.png"
image_file_path_combine = os.path.join(IMG_WEB_DIR, image_file_name_combine)
csv_url_past_day = f"{Cacti_LOGIN_URL}/graph_xport.php?local_graph_id={graph_id}&rra_id=0&graph_height=300&graph_width=1000&title_font_size=10&view_type=tree&graph_start={past_day}&graph_end={now}"
_past_one_day_save_path_csv = os.path.join(IMG_WEB_DIR, f"cacti_graph_{graph_id}_past_one_day_{now}.csv")
request = session.get(url=csv_url_past_day, headers=header, timeout=10)
csv_ret = request.content
with open(_past_one_day_save_path_csv, 'wb') as file:
file.write(csv_ret)
with open(_past_one_day_save_path_csv, 'r', encoding='utf-8', newline='') as file:
reader = csv.reader(file)
inbounds = []
outbounds = []
data_rows = []
n = 0
for row in reader:
if 'NaN' not in row:
data_rows.append(row)
if 13 <= n <= 301:
if row[1] != 'NaN':
inbounds.append(float(row[1]))
if row[3] != 'NaN':
outbounds.append(float(row[3]))
n += 1
inbound_max1 = tobit(heapq.nlargest(1, inbounds)[0])
outbound_max1 = tobit(heapq.nlargest(1, outbounds)[0])
if data_rows:
last_row = data_rows[-1]
column_2 = float(last_row[1])
column_4 = float(last_row[3])
current_inbound = tobit(column_2)
current_outbound = tobit(column_4)
max_current_without_unit = max(column_2,column_4)/1000/1000
ouput_graph_name = f"{graph_name_descr} 当前/峰值/带宽{max(current_inbound,current_outbound)}/{max(inbound_max1,outbound_max1)}/{user_bandwidth}M"
if (vip_check and max_current_without_unit < alarm_threshold) or vip_check == False:
if vip_check and max_current_without_unit < alarm_threshold:
running_logger.info(f"VIP客户低于阈值告警:{ouput_graph_name}")
if vip_check == False:
running_logger.info(f"默认告警,PING检测5次均失败:{ouput_graph_name}")
if Combine_Images_Vertically(rendered_images_fullpath_list, output_path_filename=image_file_path_combine):
BotSendInteractiveCardsMessage(erp=erp, group_id=group_id, img=image_file_name_combine, title=f"{ouput_graph_name}", deeplink_url=None)
else:
running_logger.info("Cacti合并图片失败")
else :
running_logger.info("Cacti登陆失败")
except Exception as e:
running_logger.info(f"{str(e)}")
pass
with open(CrossLine_Client_FILE, 'r', encoding='utf-8') as file:
crossline_config = json.load(file)
for client_id, client_details in crossline_config['client_info'].items():
ip_list.append(client_details['ip'])
# IP不通时发送监控图
results = Check_CrossLine_HK_VM(ip_list)
for result in results:
if result[1] != "alive":
for client_id, client_details in crossline_config['client_info'].items():
if client_details['ip'] == result[0]:
graph_id = client_details['graph_id']
graph_name_descr = client_details['name']
user_bandwidth = client_details['bandwidth']
Send_Image(graph_id, graph_name_descr, user_bandwidth,alarm_threshold=0,vip_check=False)
# 当前流量<5%总流量时发送异常告警
for client_id, client_details in crossline_config['client_info'].items():
graph_id = client_details['graph_id']
graph_name_descr = client_details['name']
user_bandwidth = client_details['bandwidth']
alarm_threshold = client_details['threshold']
if user_bandwidth >= 25:
Send_Image(graph_id, graph_name_descr, user_bandwidth, alarm_threshold, vip_check=True, )
# 自动清理旧文件
for client_id, client_details in crossline_config['client_info'].items():
graph_id = client_details['graph_id']
Delete_Old_Cacti_Files(graph_id=graph_id)



