Compare commits
5 Commits
ccb47d527f
...
b7433f0c99
| Author | SHA1 | Date | |
|---|---|---|---|
| b7433f0c99 | |||
| 1169605e6e | |||
| d9df449a17 | |||
|
|
0169bf5d6b | ||
| 04d012759c |
@ -1,12 +1,12 @@
|
|||||||
from telebot.types import Message, CallbackQuery
|
from telebot.types import Message, CallbackQuery
|
||||||
|
|
||||||
from app.bot.keyboards.active_triggers import create_region_keyboard
|
from app.bot.keyboards.active_triggers import create_region_keyboard
|
||||||
from app.bot.utils.regions import get_sorted_regions_plain
|
|
||||||
from app.bot.processors.active_triggers_processor import (
|
from app.bot.processors.active_triggers_processor import (
|
||||||
process_region_selection,
|
process_region_selection,
|
||||||
process_group_selection,
|
process_group_selection,
|
||||||
process_all_groups_request,
|
process_all_groups_request,
|
||||||
)
|
)
|
||||||
|
from app.bot.utils.regions import get_sorted_regions_plain
|
||||||
|
|
||||||
|
|
||||||
def register_active_triggers(bot, app, state_manager):
|
def register_active_triggers(bot, app, state_manager):
|
||||||
@ -22,17 +22,28 @@ def register_callbacks_active_triggers(bot,app,state_manager):
|
|||||||
@bot.callback_query_handler(func=lambda c: c.data.startswith("region_"))
|
@bot.callback_query_handler(func=lambda c: c.data.startswith("region_"))
|
||||||
def region_selected(callback_query: CallbackQuery):
|
def region_selected(callback_query: CallbackQuery):
|
||||||
region_id = callback_query.data.split("_")[1]
|
region_id = callback_query.data.split("_")[1]
|
||||||
process_region_selection(callback_query.message.chat.id,bot, region_id)
|
chat_id = callback_query.message.chat.id
|
||||||
|
bot.answer_callback_query(callback_query.id)
|
||||||
|
bot.delete_message(chat_id, callback_query.message.message_id)
|
||||||
|
process_region_selection(bot, chat_id, region_id)
|
||||||
|
|
||||||
@bot.callback_query_handler(func=lambda c: c.data.startswith("group_"))
|
@bot.callback_query_handler(func=lambda c: c.data.startswith("group_"))
|
||||||
def group_selected(callback_query: CallbackQuery):
|
def group_selected(callback_query: CallbackQuery):
|
||||||
group_id = callback_query.data.split("_")[1]
|
group_id = callback_query.data.split("_")[1]
|
||||||
process_group_selection(callback_query.message.chat.id,bot, group_id)
|
chat_id = callback_query.message.chat.id
|
||||||
|
bot.answer_callback_query(callback_query.id)
|
||||||
|
bot.delete_message(chat_id, callback_query.message.message_id)
|
||||||
|
bot.send_message(chat_id, f"Обработка...")
|
||||||
|
process_group_selection(bot, chat_id, group_id)
|
||||||
|
|
||||||
@bot.callback_query_handler(func=lambda c: c.data.startswith("all_groups_"))
|
@bot.callback_query_handler(func=lambda c: c.data.startswith("all_groups_"))
|
||||||
def all_groups_selected(callback_query: CallbackQuery):
|
def all_groups_selected(callback_query: CallbackQuery):
|
||||||
region_id = callback_query.data.split("_")[2]
|
region_id = callback_query.data.split("_")[2]
|
||||||
process_all_groups_request(callback_query.message.chat.id,bot, region_id)
|
chat_id = callback_query.message.chat.id
|
||||||
|
bot.answer_callback_query(callback_query.id)
|
||||||
|
bot.delete_message(chat_id, callback_query.message.message_id)
|
||||||
|
bot.send_message(chat_id, f"Обработка...")
|
||||||
|
process_all_groups_request(bot, chat_id, region_id)
|
||||||
|
|
||||||
@bot.callback_query_handler(func=lambda c: c.data.startswith("regions_page_"))
|
@bot.callback_query_handler(func=lambda c: c.data.startswith("regions_page_"))
|
||||||
def regions_page_selected(callback_query: CallbackQuery):
|
def regions_page_selected(callback_query: CallbackQuery):
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
from telebot import logger
|
from telebot import logger as telebot_logger
|
||||||
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton, Message
|
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton, Message, CallbackQuery
|
||||||
|
|
||||||
from config import ADMINS_LIST
|
from config import ADMINS_LIST
|
||||||
|
|
||||||
LOG_LEVELS = {
|
LOG_LEVELS = {
|
||||||
"🔴 ERROR": logging.ERROR,
|
"🔴 ERROR": logging.ERROR,
|
||||||
"🟠 WARNING": logging.WARNING,
|
"🟠 WARNING": logging.WARNING,
|
||||||
@ -11,10 +12,26 @@ LOG_LEVELS = {
|
|||||||
"🔵 DEBUG": logging.DEBUG
|
"🔵 DEBUG": logging.DEBUG
|
||||||
}
|
}
|
||||||
|
|
||||||
def register_handlers(bot,app, state_manager):
|
def set_log_level(level: int):
|
||||||
@bot.message_handler(commands=['debug'], func=lambda message: message.chat.id in ADMINS_LIST)
|
# Устанавливаем уровень для telebot и связанных библиотек
|
||||||
def debug_handler(message):
|
telebot_logger.setLevel(level)
|
||||||
|
for handler in telebot_logger.handlers:
|
||||||
|
handler.setLevel(level)
|
||||||
|
|
||||||
|
logging.getLogger("pyzabbix").setLevel(level)
|
||||||
|
logging.getLogger("requests").setLevel(level)
|
||||||
|
# logging.getLogger("urllib3").setLevel(level)
|
||||||
|
|
||||||
|
# import http.client
|
||||||
|
# if level == logging.DEBUG:
|
||||||
|
# http.client.HTTPConnection.debuglevel = 1
|
||||||
|
# else:
|
||||||
|
# http.client.HTTPConnection.debuglevel = 0
|
||||||
|
|
||||||
|
|
||||||
|
def register_handlers(bot, app, state_manager):
|
||||||
|
@bot.message_handler(commands=['debug'], func=lambda message: message.chat.id in ADMINS_LIST)
|
||||||
|
def debug_handler(message: Message):
|
||||||
chat_id = message.chat.id
|
chat_id = message.chat.id
|
||||||
markup = InlineKeyboardMarkup(row_width=1)
|
markup = InlineKeyboardMarkup(row_width=1)
|
||||||
buttons = [InlineKeyboardButton(text=level, callback_data=f"setlog_{level}") for level in LOG_LEVELS]
|
buttons = [InlineKeyboardButton(text=level, callback_data=f"setlog_{level}") for level in LOG_LEVELS]
|
||||||
@ -24,16 +41,16 @@ def register_handlers(bot,app, state_manager):
|
|||||||
bot.send_message(chat_id, "Выберите уровень логирования", reply_markup=markup)
|
bot.send_message(chat_id, "Выберите уровень логирования", reply_markup=markup)
|
||||||
|
|
||||||
@bot.callback_query_handler(func=lambda call: call.data.startswith("setlog_"))
|
@bot.callback_query_handler(func=lambda call: call.data.startswith("setlog_"))
|
||||||
def handle_log_level_callback(call):
|
def handle_log_level_callback(call: CallbackQuery):
|
||||||
message_id = call.message.message_id
|
|
||||||
level_text = call.data.replace("setlog_", "")
|
level_text = call.data.replace("setlog_", "")
|
||||||
|
chat_id = call.message.chat.id
|
||||||
|
message_id = call.message.message_id
|
||||||
|
|
||||||
if level_text in LOG_LEVELS:
|
if level_text in LOG_LEVELS:
|
||||||
level = LOG_LEVELS[level_text]
|
level = LOG_LEVELS[level_text]
|
||||||
logger.setLevel(level)
|
set_log_level(level)
|
||||||
for handler in logger.handlers:
|
bot.answer_callback_query(call.id, f"✅ Уровень логирования установлен: {level_text}")
|
||||||
handler.setLevel(level)
|
bot.delete_message(chat_id, message_id)
|
||||||
bot.answer_callback_query(call.id, f"✅ Уровень логирования: {level_text}")
|
bot.send_message(chat_id, f"📋 Логгер переведён в режим: {level_text}")
|
||||||
bot.delete_message(call.message.chat.id, message_id)
|
|
||||||
bot.send_message(call.message.chat.id, f"📋 Логгер переведён в режим: {level_text}")
|
|
||||||
else:
|
else:
|
||||||
bot.answer_callback_query(call.id, "❌ Неизвестный уровень логирования")
|
bot.answer_callback_query(call.id, "❌ Неизвестный уровень логирования")
|
||||||
|
|||||||
@ -30,10 +30,3 @@ def create_region_keyboard(regions, page, page_size=REGIONS_PER_PAGE):
|
|||||||
markup.add(cancel_button)
|
markup.add(cancel_button)
|
||||||
|
|
||||||
return markup
|
return markup
|
||||||
|
|
||||||
def create_group_keyboard(groups, region_id):
|
|
||||||
markup = InlineKeyboardMarkup()
|
|
||||||
for group in groups:
|
|
||||||
markup.add(InlineKeyboardButton(text=group['name'], callback_data=f"group_{group['groupid']}"))
|
|
||||||
markup.add(InlineKeyboardButton(text="Все группы региона\n(Долгое выполнение)", callback_data=f"all_groups_{region_id}"))
|
|
||||||
return markup
|
|
||||||
|
|||||||
23
app/bot/keyboards/groups.py
Normal file
23
app/bot/keyboards/groups.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
|
def create_groups_keyboard(groups, region_id):
|
||||||
|
"""
|
||||||
|
Формирует InlineKeyboardMarkup для выбора группы хостов.
|
||||||
|
|
||||||
|
:param groups: список словарей с группами, у каждой есть 'name' и 'groupid'
|
||||||
|
:param region_id: id региона, нужен для callback_data кнопки "Все группы региона"
|
||||||
|
:return: telebot.types.InlineKeyboardMarkup
|
||||||
|
"""
|
||||||
|
markup = InlineKeyboardMarkup()
|
||||||
|
for group in groups:
|
||||||
|
markup.add(InlineKeyboardButton(
|
||||||
|
text=group['name'],
|
||||||
|
callback_data=f"group_{group['groupid']}"
|
||||||
|
))
|
||||||
|
markup.add(InlineKeyboardButton(
|
||||||
|
text="Все группы региона\n(Долгое выполнение)",
|
||||||
|
callback_data=f"all_groups_{region_id}"
|
||||||
|
))
|
||||||
|
cancel_button = InlineKeyboardButton("Отмена", callback_data="cancel_input")
|
||||||
|
markup.add(cancel_button)
|
||||||
|
return markup
|
||||||
@ -1,19 +1,20 @@
|
|||||||
from telebot import types
|
from telebot.types import InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
from app.bot.keyboards.main_menu import get_main_menu
|
|
||||||
from app.bot.utils.zabbix import get_region_groups, get_all_groups_for_region, fetch_filtered_triggers
|
|
||||||
from app.bot.utils.tg_formatter import format_trigger_message # ⬅️ добавлено
|
|
||||||
|
|
||||||
def process_region_selection(bot,chat_id, region_id):
|
from app.bot.keyboards.groups import create_groups_keyboard
|
||||||
|
from app.bot.keyboards.main_menu import get_main_menu
|
||||||
|
from app.bot.utils.tg_formatter import format_trigger_for_tg
|
||||||
|
from app.bot.utils.zabbix_alt import (
|
||||||
|
get_region_groups,
|
||||||
|
get_all_groups_for_region,
|
||||||
|
fetch_triggers_data)
|
||||||
|
|
||||||
|
|
||||||
|
def process_region_selection(bot, chat_id, region_id):
|
||||||
try:
|
try:
|
||||||
groups = get_region_groups(region_id)
|
groups = get_region_groups(region_id)
|
||||||
if not groups:
|
if not groups:
|
||||||
return bot.send_message(chat_id, "Нет групп хостов для этого региона.")
|
return bot.send_message(chat_id, "Нет групп хостов для этого региона.")
|
||||||
|
markup = create_groups_keyboard(groups, region_id)
|
||||||
markup = types.InlineKeyboardMarkup()
|
|
||||||
for group in groups:
|
|
||||||
markup.add(types.InlineKeyboardButton(text=group['name'], callback_data=f"group_{group['groupid']}"))
|
|
||||||
markup.add(types.InlineKeyboardButton(text="Все группы региона\n(Долгое выполнение)", callback_data=f"all_groups_{region_id}"))
|
|
||||||
|
|
||||||
bot.send_message(chat_id, "Выберите группу хостов:", reply_markup=markup)
|
bot.send_message(chat_id, "Выберите группу хостов:", reply_markup=markup)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
bot.send_message(chat_id, f"Ошибка при получении групп: {str(e)}", reply_markup=get_main_menu())
|
bot.send_message(chat_id, f"Ошибка при получении групп: {str(e)}", reply_markup=get_main_menu())
|
||||||
@ -21,11 +22,16 @@ def process_region_selection(bot,chat_id, region_id):
|
|||||||
|
|
||||||
def process_group_selection(bot, chat_id, group_id):
|
def process_group_selection(bot, chat_id, group_id):
|
||||||
try:
|
try:
|
||||||
triggers = fetch_filtered_triggers(group_id)
|
triggers = fetch_triggers_data(group_id)
|
||||||
if not triggers:
|
if not triggers:
|
||||||
bot.send_message(chat_id, "Нет активных событий.")
|
bot.send_message(chat_id, "Нет активных событий.")
|
||||||
else:
|
return
|
||||||
send_trigger_messages(chat_id, triggers)
|
|
||||||
|
for trigger in triggers:
|
||||||
|
text, url = format_trigger_for_tg(trigger)
|
||||||
|
markup = InlineKeyboardMarkup()
|
||||||
|
markup.add(InlineKeyboardButton(text="Открыть график", url=url))
|
||||||
|
bot.send_message(chat_id, text, reply_markup=markup, parse_mode="HTML")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
bot.send_message(chat_id, f"Ошибка при получении событий: {str(e)}")
|
bot.send_message(chat_id, f"Ошибка при получении событий: {str(e)}")
|
||||||
|
|
||||||
@ -36,21 +42,21 @@ def process_all_groups_request(bot, chat_id, region_id):
|
|||||||
groups = get_all_groups_for_region(region_id)
|
groups = get_all_groups_for_region(region_id)
|
||||||
for group in groups:
|
for group in groups:
|
||||||
try:
|
try:
|
||||||
triggers = fetch_filtered_triggers(group['groupid'])
|
triggers = fetch_triggers_data(group['groupid'])
|
||||||
if triggers:
|
if triggers:
|
||||||
all_triggers.extend(triggers)
|
all_triggers.extend(triggers)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if all_triggers:
|
if not all_triggers:
|
||||||
send_trigger_messages(chat_id, all_triggers)
|
|
||||||
else:
|
|
||||||
bot.send_message(chat_id, "Нет активных событий.")
|
bot.send_message(chat_id, "Нет активных событий.")
|
||||||
|
return
|
||||||
|
|
||||||
|
for trigger in all_triggers:
|
||||||
|
text, url = format_trigger_for_tg(trigger)
|
||||||
|
markup = InlineKeyboardMarkup()
|
||||||
|
markup.add(InlineKeyboardButton(text="Открыть график", url=url))
|
||||||
|
bot.send_message(chat_id, text, reply_markup=markup, parse_mode="HTML")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
bot.send_message(chat_id, f"Ошибка при получении данных: {str(e)}")
|
bot.send_message(chat_id, f"Ошибка при получении данных: {str(e)}")
|
||||||
|
|
||||||
|
|
||||||
def send_trigger_messages(chat_id, triggers):
|
|
||||||
for trigger in triggers:
|
|
||||||
text = format_trigger_message(trigger)
|
|
||||||
bot.send_message(chat_id, text, parse_mode="MarkdownV2")
|
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
from telebot.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, MessageID
|
from telebot.types import Message, InlineKeyboardMarkup, InlineKeyboardButton, MessageID
|
||||||
from app.bot.keyboards.settings_menu import get_settings_menu
|
|
||||||
from app.extensions.db import db
|
|
||||||
from app import Regions, Subscriptions
|
from app import Regions, Subscriptions
|
||||||
from app.bot.utils.tg_audit import log_user_event
|
|
||||||
from app.bot.constants import UserStates
|
from app.bot.constants import UserStates
|
||||||
|
from app.bot.keyboards.settings_menu import get_settings_menu
|
||||||
|
from app.bot.utils.tg_audit import log_user_event
|
||||||
|
from app.extensions.db import db
|
||||||
|
|
||||||
|
|
||||||
def process_subscription_button(message: Message, app, bot, chat_id: int, state_manager, bot_message: MessageID):
|
def process_subscription_button(message: Message, app, bot, chat_id: int, state_manager, bot_message: MessageID):
|
||||||
@ -17,7 +18,8 @@ def process_subscription_button(message: Message, app, bot, chat_id: int, state_
|
|||||||
reply_markup=markup)
|
reply_markup=markup)
|
||||||
|
|
||||||
def delayed_handler(msg):
|
def delayed_handler(msg):
|
||||||
process_subscription_button(msg, app, bot, chat_id, state_manager)
|
message_id = msg.message_id
|
||||||
|
process_subscription_button(msg, app, bot, chat_id, state_manager, message_id)
|
||||||
|
|
||||||
bot.register_next_step_handler(message, delayed_handler)
|
bot.register_next_step_handler(message, delayed_handler)
|
||||||
return
|
return
|
||||||
|
|||||||
@ -1,35 +1,44 @@
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
from pytz import timezone
|
from pytz import timezone
|
||||||
|
|
||||||
from app.bot.utils.tg_escape_chars import escape_telegram_chars
|
from app.bot.utils.tg_escape_chars import escape_telegram_chars
|
||||||
|
from config import ZABBIX_URL, ZABBIX_TZ
|
||||||
|
|
||||||
def format_trigger_message(trigger, zabbix_url: str) -> str:
|
|
||||||
tz = timezone('Europe/Moscow')
|
def format_trigger_for_tg(trigger):
|
||||||
|
"""
|
||||||
|
Формирует текст сообщения для одного триггера
|
||||||
|
и возвращает (text, inline_buttons_data)
|
||||||
|
"""
|
||||||
priority_map = {'4': 'HIGH', '5': 'DISASTER'}
|
priority_map = {'4': 'HIGH', '5': 'DISASTER'}
|
||||||
|
priority_map_emoji = {'4': '⚠️','5': '⛔️'}
|
||||||
event_time_epoch = int(trigger.get('lastEvent', {}).get('clock', trigger.get('lastchange', 0)))
|
event_time_epoch = int(trigger['lastEvent']['clock'])
|
||||||
event_time = datetime.fromtimestamp(event_time_epoch, tz=tz)
|
event_time = datetime.fromtimestamp(event_time_epoch, tz=timezone(ZABBIX_TZ))
|
||||||
event_time_formatted = event_time.strftime('%Y-%m-%d %H:%M:%S Мск')
|
event_time_formatted = event_time.strftime('%Y-%m-%d %H:%M:%S Мск')
|
||||||
|
|
||||||
host = trigger.get('hosts', [{}])[0].get('name', 'Неизвестно')
|
description = escape_telegram_chars(trigger['description'])
|
||||||
priority = priority_map.get(str(trigger.get('priority')), 'Неизвестно')
|
host = trigger['hosts'][0]['name']
|
||||||
description = escape_telegram_chars(trigger.get('description', '')).replace("{HOST.NAME}", host)
|
priority = priority_map.get(trigger['priority'], 'Неизвестно')
|
||||||
|
icon = priority_map_emoji.get(trigger['priority'], 'Неизвестно')
|
||||||
items = trigger.get('items', [])
|
description = description.replace("{HOST.NAME}", host)
|
||||||
item_ids = [item['itemid'] for item in items]
|
for i, item in enumerate(trigger['items']):
|
||||||
|
|
||||||
for i, item in enumerate(items):
|
|
||||||
placeholder = f"{{ITEM.LASTVALUE{i + 1}}}"
|
placeholder = f"{{ITEM.LASTVALUE{i + 1}}}"
|
||||||
if placeholder in description:
|
if placeholder in description:
|
||||||
description = description.replace(placeholder, item.get('lastvalue', '?'))
|
description = description.replace(placeholder, item['lastvalue'])
|
||||||
|
|
||||||
batchgraph_link = f"{zabbix_url}/history.php?action=batchgraph&"
|
item_ids = [item['itemid'] for item in trigger['items']]
|
||||||
|
batchgraph_link = f"{ZABBIX_URL}/history.php?action=batchgraph&"
|
||||||
batchgraph_link += "&".join([f"itemids[{item_id}]={item_id}" for item_id in item_ids])
|
batchgraph_link += "&".join([f"itemids[{item_id}]={item_id}" for item_id in item_ids])
|
||||||
batchgraph_link += "&graphtype=0"
|
batchgraph_link += "&graphtype=0"
|
||||||
|
|
||||||
return (
|
text = (
|
||||||
f"<b>Host</b>: {host}\n"
|
f"<b>Host</b>: {host}\n"
|
||||||
f"<b>Описание</b>: {description}\n"
|
f"<b>Описание</b>: {description}\n"
|
||||||
f"<b>Критичность</b>: {priority}\n"
|
f"<b>Критичность</b>: {icon} {priority}\n"
|
||||||
f"<b>Время создания</b>: {event_time_formatted}\n"
|
f"<b>Время создания</b>: {event_time_formatted}\n"
|
||||||
f'<b>URL</b>: <a href="{batchgraph_link}">Ссылка на график</a>'
|
# f'<b>URL</b>: <a href="{batchgraph_link}">Ссылка на график</a>'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Возвращаем текст и ссылку, чтобы потом сделать inline кнопку
|
||||||
|
return text, batchgraph_link
|
||||||
|
|||||||
@ -1,119 +0,0 @@
|
|||||||
import time
|
|
||||||
from datetime import datetime
|
|
||||||
from pytz import timezone
|
|
||||||
from pyzabbix import ZabbixAPI, ZabbixAPIException
|
|
||||||
from telebot import logger
|
|
||||||
|
|
||||||
from config import ZABBIX_URL, ZABBIX_API_TOKEN, ZABBIX_VERIFY_SSL, ZABBIX_TZ
|
|
||||||
from app.bot.utils.tg_escape_chars import escape_telegram_chars
|
|
||||||
TZ = timezone(ZABBIX_TZ)
|
|
||||||
verify_ssl = ZABBIX_VERIFY_SSL
|
|
||||||
|
|
||||||
def get_region_groups(region_id: str):
|
|
||||||
"""
|
|
||||||
Получает список групп, имя которых содержит регион region_id, исключая 'test'.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
zapi = ZabbixAPI(ZABBIX_URL)
|
|
||||||
zapi.login(api_token=ZABBIX_API_TOKEN)
|
|
||||||
zapi.session.verify = verify_ssl
|
|
||||||
|
|
||||||
host_groups = zapi.hostgroup.get(output=["groupid", "name"], search={"name": region_id})
|
|
||||||
filtered_groups = [group for group in host_groups if 'test' not in group['name'].lower()]
|
|
||||||
return filtered_groups
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error getting region groups for '{region_id}': {e}")
|
|
||||||
return []
|
|
||||||
|
|
||||||
def get_all_groups_for_region(region_id: str):
|
|
||||||
"""
|
|
||||||
Аналогично get_region_groups, получение всех групп по региону.
|
|
||||||
"""
|
|
||||||
return get_region_groups(region_id)
|
|
||||||
|
|
||||||
def fetch_filtered_triggers(group_id):
|
|
||||||
"""
|
|
||||||
Получение и фильтрация триггеров с severities 4 и 5,
|
|
||||||
формирование HTML сообщений для отправки в Telegram.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
zapi = ZabbixAPI(ZABBIX_URL)
|
|
||||||
zapi.login(api_token=ZABBIX_API_TOKEN)
|
|
||||||
zapi.session.verify = verify_ssl
|
|
||||||
|
|
||||||
problems = zapi.problem.get(
|
|
||||||
severities=[4, 5],
|
|
||||||
suppressed=0,
|
|
||||||
acknowledged=0,
|
|
||||||
groupids=group_id
|
|
||||||
)
|
|
||||||
trigger_ids = [problem["objectid"] for problem in problems]
|
|
||||||
|
|
||||||
if not trigger_ids:
|
|
||||||
return []
|
|
||||||
|
|
||||||
triggers = zapi.trigger.get(
|
|
||||||
triggerids=trigger_ids,
|
|
||||||
output=["triggerid", "description", "priority"],
|
|
||||||
selectHosts=["hostid", "name"],
|
|
||||||
monitored=1,
|
|
||||||
expandDescription=1,
|
|
||||||
expandComment=1,
|
|
||||||
selectItems=["itemid", "lastvalue"],
|
|
||||||
selectLastEvent=["clock", "eventid"]
|
|
||||||
)
|
|
||||||
|
|
||||||
events = zapi.event.get(
|
|
||||||
severities=[4, 5],
|
|
||||||
objectids=trigger_ids,
|
|
||||||
select_alerts="mediatype"
|
|
||||||
)
|
|
||||||
|
|
||||||
pnet_mediatypes = {"Pnet integration JS 2025", "Pnet integration JS 2024", "Pnet integration new2"}
|
|
||||||
|
|
||||||
pnet_triggers = []
|
|
||||||
event_dict = {event["objectid"]: event for event in events}
|
|
||||||
|
|
||||||
for trigger in triggers:
|
|
||||||
event = event_dict.get(trigger["triggerid"])
|
|
||||||
if event:
|
|
||||||
for alert in event["alerts"]:
|
|
||||||
if alert["mediatypes"] and alert["mediatypes"][0]["name"] in pnet_mediatypes:
|
|
||||||
pnet_triggers.append(trigger)
|
|
||||||
break
|
|
||||||
|
|
||||||
triggers_sorted = sorted(pnet_triggers, key=lambda t: int(t['lastEvent']['clock']))
|
|
||||||
|
|
||||||
|
|
||||||
priority_map = {'4': 'HIGH', '5': 'DISASTER'}
|
|
||||||
trigger_messages = []
|
|
||||||
|
|
||||||
for trigger in triggers_sorted:
|
|
||||||
event_time_epoch = int(trigger['lastEvent']['clock'])
|
|
||||||
event_time = datetime.fromtimestamp(event_time_epoch, tz=TZ)
|
|
||||||
description = escape_telegram_chars(trigger['description'])
|
|
||||||
host = trigger['hosts'][0]['name']
|
|
||||||
priority = priority_map.get(trigger['priority'], 'Неизвестно')
|
|
||||||
item_ids = [item['itemid'] for item in trigger['items']]
|
|
||||||
batchgraph_link = f"{ZABBIX_URL}/history.php?action=batchgraph&"
|
|
||||||
batchgraph_link += "&".join([f"itemids[{item_id}]={item_id}" for item_id in item_ids])
|
|
||||||
batchgraph_link += "&graphtype=0"
|
|
||||||
description = description.replace("{HOST.NAME}", host)
|
|
||||||
for i, item in enumerate(trigger['items']):
|
|
||||||
lastvalue_placeholder = f"{{ITEM.LASTVALUE{i + 1}}}"
|
|
||||||
if lastvalue_placeholder in description:
|
|
||||||
description = description.replace(lastvalue_placeholder, item['lastvalue'])
|
|
||||||
event_time_formatted = event_time.strftime('%Y-%m-%d %H:%M:%S Мск')
|
|
||||||
message = (f"<b>Host</b>: {host}\n"
|
|
||||||
f"<b>Описание</b>: {description}\n"
|
|
||||||
f"<b>Критичность</b>: {priority}\n"
|
|
||||||
f"<b>Время создания</b>: {event_time_formatted}\n"
|
|
||||||
f'<b>URL</b>: <a href="{batchgraph_link}">Ссылка на график</a>')
|
|
||||||
trigger_messages.append(message)
|
|
||||||
|
|
||||||
logger.info(f"Fetched {len(triggers_sorted)} triggers for group {group_id}.")
|
|
||||||
return trigger_messages
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
logger.error(f"Error fetching triggers for group {group_id}: {e}")
|
|
||||||
return []
|
|
||||||
103
app/bot/utils/zabbix_alt.py
Normal file
103
app/bot/utils/zabbix_alt.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
from pyzabbix import ZabbixAPI, ZabbixAPIException
|
||||||
|
from telebot import logger
|
||||||
|
|
||||||
|
from config import ZABBIX_URL, ZABBIX_API_TOKEN, ZABBIX_VERIFY_SSL
|
||||||
|
|
||||||
|
|
||||||
|
def get_region_groups(region_id: str):
|
||||||
|
"""
|
||||||
|
Получает список групп, имя которых содержит регион region_id, исключая 'test' и группы, не соответствующие шаблону 'имя_число'.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
zapi = ZabbixAPI(ZABBIX_URL)
|
||||||
|
zapi.login(api_token=ZABBIX_API_TOKEN)
|
||||||
|
zapi.session.verify = ZABBIX_VERIFY_SSL
|
||||||
|
|
||||||
|
host_groups = zapi.hostgroup.get(output=["groupid", "name"], search={"name": region_id})
|
||||||
|
|
||||||
|
pattern = re.compile(r'.+_\d+$') # строка с нижним подчёркиванием перед числом в конце
|
||||||
|
|
||||||
|
filtered_groups = [
|
||||||
|
group for group in host_groups
|
||||||
|
if 'test' not in group['name'].lower() and pattern.match(group['name'])
|
||||||
|
]
|
||||||
|
return filtered_groups
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[Zabbix] Error getting region groups for '{region_id}': {e}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
def get_all_groups_for_region(region_id: str):
|
||||||
|
"""
|
||||||
|
Аналогично get_region_groups, получение всех групп по региону.
|
||||||
|
"""
|
||||||
|
return get_region_groups(region_id)
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_triggers_data(group_id):
|
||||||
|
"""
|
||||||
|
Возвращает список триггеров с необходимыми данными,
|
||||||
|
без форматирования сообщений.
|
||||||
|
"""
|
||||||
|
pnet_mediatypes = {"Pnet integration JS 2025", "Pnet integration JS 2024", "Pnet integration new2"}
|
||||||
|
start_time = time.time()
|
||||||
|
try:
|
||||||
|
zapi = ZabbixAPI(ZABBIX_URL)
|
||||||
|
zapi.login(api_token=ZABBIX_API_TOKEN)
|
||||||
|
|
||||||
|
# Получаем проблемы с высокой и критической важностью
|
||||||
|
problems = zapi.problem.get(
|
||||||
|
severities=[4, 5],
|
||||||
|
suppressed=0,
|
||||||
|
acknowledged=0,
|
||||||
|
groupids=group_id
|
||||||
|
)
|
||||||
|
trigger_ids = [problem["objectid"] for problem in problems]
|
||||||
|
|
||||||
|
if not trigger_ids:
|
||||||
|
logger.info(f"No triggers found for group {group_id}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
triggers = zapi.trigger.get(
|
||||||
|
triggerids=trigger_ids,
|
||||||
|
output=["triggerid", "description", "priority"],
|
||||||
|
selectHosts=["hostid", "name"],
|
||||||
|
monitored=1,
|
||||||
|
expandDescription=1,
|
||||||
|
expandComment=1,
|
||||||
|
selectItems=["itemid", "lastvalue"],
|
||||||
|
selectLastEvent=["clock", "eventid"]
|
||||||
|
)
|
||||||
|
|
||||||
|
events = zapi.event.get(
|
||||||
|
severities=[4, 5],
|
||||||
|
objectids=trigger_ids,
|
||||||
|
select_alerts="mediatype"
|
||||||
|
)
|
||||||
|
|
||||||
|
event_dict = {event["objectid"]: event for event in events}
|
||||||
|
|
||||||
|
pnet_triggers = []
|
||||||
|
for trigger in triggers:
|
||||||
|
event = event_dict.get(trigger["triggerid"])
|
||||||
|
if event:
|
||||||
|
for alert in event["alerts"]:
|
||||||
|
if alert["mediatypes"] and alert["mediatypes"][0]["name"] in pnet_mediatypes:
|
||||||
|
pnet_triggers.append(trigger)
|
||||||
|
break
|
||||||
|
|
||||||
|
triggers_sorted = sorted(pnet_triggers, key=lambda t: int(t['lastEvent']['clock']))
|
||||||
|
logger.debug(f"Found {len(pnet_triggers)} pnet triggers for group {group_id}")
|
||||||
|
end_time = time.time()
|
||||||
|
logger.info(f"[Zabbix] Fetched {len(triggers_sorted)} triggers for group {group_id} in {end_time - start_time:.2f} seconds.")
|
||||||
|
return triggers_sorted
|
||||||
|
|
||||||
|
except ZabbixAPIException as e:
|
||||||
|
logger.error(f"[Zabbix] Zabbix API error for group {group_id}: {e}")
|
||||||
|
return []
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"[Zabbix] Unexpected error fetching triggers for group {group_id}: {e}")
|
||||||
|
return []
|
||||||
@ -11,7 +11,7 @@ REGIONS_PER_PAGE = os.getenv('REGIONS_PER_PAGE', 10)
|
|||||||
ZABBIX_API_TOKEN = os.getenv('ZABBIX_API_TOKEN')
|
ZABBIX_API_TOKEN = os.getenv('ZABBIX_API_TOKEN')
|
||||||
ZABBIX_URL = os.getenv('ZABBIX_URL')
|
ZABBIX_URL = os.getenv('ZABBIX_URL')
|
||||||
ZABBIX_VERIFY_SSL = os.getenv('ZABBIX_VERIFY_SSL', True)
|
ZABBIX_VERIFY_SSL = os.getenv('ZABBIX_VERIFY_SSL', True)
|
||||||
ZABBIX_TZ = os.getenv('ZABBIX_TZ', 'Europe/Moscow')
|
ZABBIX_TZ = os.getenv('TZ', 'Europe/Moscow')
|
||||||
#Настройки Flask и Telegram bot
|
#Настройки Flask и Telegram bot
|
||||||
basedir = os.path.abspath(os.path.dirname(__file__))
|
basedir = os.path.abspath(os.path.dirname(__file__))
|
||||||
DB_ABS_PATH = os.path.join(basedir, 'db/telezab.db')
|
DB_ABS_PATH = os.path.join(basedir, 'db/telezab.db')
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user