From 12c124863e9920bc10c2093f4f1ff027860a3b0a Mon Sep 17 00:00:00 2001 From: sergey Date: Sun, 13 Apr 2025 15:30:37 +0300 Subject: [PATCH 1/4] add fail check and edit message --- config/.env-template | 1 + config/config.py | 2 ++ docker/docker-compose.yaml | 2 +- pyproject.toml | 2 +- telegram/__init__.py | 2 ++ telegram/message.py | 32 ++++++++++++++++++++++++++++++++ zabbix/zabbix_api.py | 7 +++++++ 7 files changed, 46 insertions(+), 2 deletions(-) diff --git a/config/.env-template b/config/.env-template index 8b59671..cf0bd90 100755 --- a/config/.env-template +++ b/config/.env-template @@ -5,6 +5,7 @@ CFG__ZABBIX__URL=https://example.com CFG__ZABBIX__TOKEN=string CFG__ZABBIX__MIN_SEVERITY=0 CFG__ZABBIX__UPD_INTERVAL=60 +CFG__ZABBIX__ALERT_FAIL_COUNT=3 CFG__TGBOT__TOKEN=string CFG__TGBOT__CHAT_ID=00000000 diff --git a/config/config.py b/config/config.py index 9c0c501..d41d4e4 100755 --- a/config/config.py +++ b/config/config.py @@ -49,6 +49,8 @@ class ZabbixConfig(BaseModel): token: str min_severity: int upd_interval: int + alert_fail_count: int + current_fail: int = 0 class Settings(BaseSettings): diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 369c50e..b9a6426 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -10,7 +10,7 @@ services: command: [redis-server, --protected-mode yes, --port 6379, --requirepass, P@ssw0rd!] tg-bot: - image: git.sm8255082.ru/osnova/zbx-tg-bot:2.0.0 + image: git.sm8255082.ru/osnova/zbx-tg-bot:2.0.1 restart: always depends_on: - redis diff --git a/pyproject.toml b/pyproject.toml index 0c7b748..069f818 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "zbx-tg-bot" -version = "2.0.0" +version = "2.0.1" description = "telegram bot for telegram-zabbix dashboard" requires-python = ">=3.13" dependencies = [ diff --git a/telegram/__init__.py b/telegram/__init__.py index 9a89e27..3427200 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -1,6 +1,7 @@ from .message import ( send_message, del_message, + edit_message, ) from .bot import start_bot @@ -8,4 +9,5 @@ __all__ = [ "send_message", "del_message", "start_bot", + "edit_message", ] diff --git a/telegram/message.py b/telegram/message.py index 2a3922f..c6c0650 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -45,6 +45,38 @@ async def send_message(message: str, event_id: int) -> dict: return {"status": e} +async def edit_message( + message_id: int, + new_message: str, +) -> dict: + url = f"https://api.telegram.org/bot{conf.tgbot.token}/editMessageText" + async with aiohttp.ClientSession() as session: + try: + async with session.post( + url, + json={ + "chat_id": conf.tgbot.chat_id, + "message_id": message_id, + "text": new_message, + }, + ) as response: + if response.status == 200: + log.info(f"Message ID {message_id} edited") + return { + "status": response.status, + } + else: + log.warning( + f"Message ID {message_id} NOT edited. Response status: {response.status}" + ) + return { + "status": response.status, + } + except Exception as e: + log.warning(f"Exception: {e}") + return {"status": e} + + async def del_message( message_id: int, ) -> dict: diff --git a/zabbix/zabbix_api.py b/zabbix/zabbix_api.py index 44c6b2a..4f345a9 100644 --- a/zabbix/zabbix_api.py +++ b/zabbix/zabbix_api.py @@ -40,9 +40,16 @@ def get_active_problems() -> dict: event["host"] = event.pop("hosts", None)[0]["host"] events_dict[event["eventid"]] = event events_dict["event_ids"].append(event["eventid"]) + if conf.zabbix.current_fail: + conf.zabbix.current_fail = 0 return events_dict except: log.warning("Get event from zabbix error") + if conf.zabbix.current_fail == conf.zabbix.alert_fail_count: + log.warning(f"Zabbix connection error. Count {conf.zabbix.current_fail}") + else: + conf.zabbix.current_fail += 1 + log.warning(f"Zabbix connection error. Count {conf.zabbix.current_fail}") def event_acknowledge(event_id: int, mute_time: int, muted_by: str): From ac78933106ad231048c0f1a86d50821316d18a07 Mon Sep 17 00:00:00 2001 From: sergey Date: Mon, 14 Apr 2025 14:12:48 +0300 Subject: [PATCH 2/4] check zabbix api --- config/.env-template | 3 ++ config/config.py | 6 +++- docker/docker-compose.yaml | 4 +++ telegram/__init__.py | 4 +-- telegram/message.py | 59 +++++++++++++++++--------------------- zabbix/zabbix_api.py | 43 ++++++++++++++++++++++----- 6 files changed, 77 insertions(+), 42 deletions(-) diff --git a/config/.env-template b/config/.env-template index cf0bd90..5816293 100755 --- a/config/.env-template +++ b/config/.env-template @@ -6,6 +6,9 @@ CFG__ZABBIX__TOKEN=string CFG__ZABBIX__MIN_SEVERITY=0 CFG__ZABBIX__UPD_INTERVAL=60 CFG__ZABBIX__ALERT_FAIL_COUNT=3 +CFG__ZABBIX__ALERT_TREAD_ID=0 +CFG__ZABBIX__ALERT_TEXT_UP=Zabbix service UP +CFG__ZABBIX__ALERT_TEXT_DOWN=Zabbix service DOWN CFG__TGBOT__TOKEN=string CFG__TGBOT__CHAT_ID=00000000 diff --git a/config/config.py b/config/config.py index d41d4e4..3720822 100755 --- a/config/config.py +++ b/config/config.py @@ -50,7 +50,11 @@ class ZabbixConfig(BaseModel): min_severity: int upd_interval: int alert_fail_count: int - current_fail: int = 0 + alert_tread_id: int + alert_text_up: str + alert_text_down: str + change_state_count: int = 0 + api_state: str = "UP" class Settings(BaseSettings): diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index b9a6426..b752209 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -22,6 +22,10 @@ services: - CFG__ZABBIX__TOKEN=string - CFG__ZABBIX__MIN_SEVERITY=2 - CFG__ZABBIX__UPD_INTERVAL=30 + - CFG__ZABBIX__ALERT_FAIL_COUNT=3 + - CFG__ZABBIX__ALERT_TREAD_ID=0 + - CFG__ZABBIX__ALERT_TEXT_UP=Zabbix service UP + - CFG__ZABBIX__ALERT_TEXT_DOWN=Zabbix service DOWN - CFG__TGBOT__TOKEN=string - CFG__TGBOT__CHAT_ID=000000 diff --git a/telegram/__init__.py b/telegram/__init__.py index 3427200..0215468 100644 --- a/telegram/__init__.py +++ b/telegram/__init__.py @@ -1,7 +1,7 @@ from .message import ( send_message, del_message, - edit_message, + send_zabbix_api_alert, ) from .bot import start_bot @@ -9,5 +9,5 @@ __all__ = [ "send_message", "del_message", "start_bot", - "edit_message", + "send_zabbix_api_alert", ] diff --git a/telegram/message.py b/telegram/message.py index c6c0650..ee264da 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -45,38 +45,6 @@ async def send_message(message: str, event_id: int) -> dict: return {"status": e} -async def edit_message( - message_id: int, - new_message: str, -) -> dict: - url = f"https://api.telegram.org/bot{conf.tgbot.token}/editMessageText" - async with aiohttp.ClientSession() as session: - try: - async with session.post( - url, - json={ - "chat_id": conf.tgbot.chat_id, - "message_id": message_id, - "text": new_message, - }, - ) as response: - if response.status == 200: - log.info(f"Message ID {message_id} edited") - return { - "status": response.status, - } - else: - log.warning( - f"Message ID {message_id} NOT edited. Response status: {response.status}" - ) - return { - "status": response.status, - } - except Exception as e: - log.warning(f"Exception: {e}") - return {"status": e} - - async def del_message( message_id: int, ) -> dict: @@ -99,9 +67,36 @@ async def del_message( log.warning( f"Message ID {message_id} NOT deleted. Response status: {response.status}" ) + return { "status": response.status, } except Exception as e: log.warning(f"Exception: {e}") return {"status": e} + + +async def send_zabbix_api_alert(message): + url = f"https://api.telegram.org/bot{conf.tgbot.token}/sendMessage" + params = { + "chat_id": conf.tgbot.chat_id, + "message_thread_id": conf.zabbix.alert_tread_id, + "text": message, + } + async with aiohttp.ClientSession() as session: + try: + async with session.post( + url, + json=params, + ) as response: + log.info(f"Response status: {response.status}") + resp = await response.json() + if response.status == 200: + log.info(f"Message with ID: {resp['result']['message_id']} send") + return {"status": response.status} + else: + log.warning(f"Message not send. Response status: {response.status}") + return {"status": response.status} + except Exception as e: + log.warning(f"Exception: {e}") + return {"status": e} diff --git a/zabbix/zabbix_api.py b/zabbix/zabbix_api.py index 4f345a9..668ed60 100644 --- a/zabbix/zabbix_api.py +++ b/zabbix/zabbix_api.py @@ -3,11 +3,45 @@ import logging as log from pyexpat.errors import messages from zabbix_utils import ZabbixAPI +import telegram from config import conf from datetime import datetime, timedelta +def check_state(success: bool) -> None: + if success: + if conf.zabbix.api_state == "UP": + log.info("Zabbix API is UP") + conf.zabbix.change_state_count = 0 + else: + if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count: + log.warning( + f"Zabbix API state changed to UP. Count {conf.zabbix.change_state_count}" + ) + send_result = telegram.send_zabbix_api_alert(conf.zabbix.alert_text_up) + if send_result["status"] == 200: + conf.zabbix.change_state_count = 0 + else: + conf.zabbix.change_state_count += 1 + else: + if conf.zabbix.api_state == "DOWN": + log.info("Zabbix API is DOWN") + conf.zabbix.change_state_count = 0 + else: + if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count: + log.warning( + f"Zabbix API state changed to DOWN. Count {conf.zabbix.change_state_count}" + ) + send_result = telegram.send_zabbix_api_alert( + conf.zabbix.alert_text_down + ) + if send_result["status"] == 200: + conf.zabbix.change_state_count = 0 + else: + conf.zabbix.change_state_count += 1 + + def get_active_problems() -> dict: api = ZabbixAPI(url=conf.zabbix.url, token=conf.zabbix.token) try: @@ -40,16 +74,11 @@ def get_active_problems() -> dict: event["host"] = event.pop("hosts", None)[0]["host"] events_dict[event["eventid"]] = event events_dict["event_ids"].append(event["eventid"]) - if conf.zabbix.current_fail: - conf.zabbix.current_fail = 0 + check_state(True) return events_dict except: log.warning("Get event from zabbix error") - if conf.zabbix.current_fail == conf.zabbix.alert_fail_count: - log.warning(f"Zabbix connection error. Count {conf.zabbix.current_fail}") - else: - conf.zabbix.current_fail += 1 - log.warning(f"Zabbix connection error. Count {conf.zabbix.current_fail}") + check_state(False) def event_acknowledge(event_id: int, mute_time: int, muted_by: str): From e9ee7bb8b07e78fa397c12beda1b1b8c1851afba Mon Sep 17 00:00:00 2001 From: sergey Date: Mon, 14 Apr 2025 15:49:47 +0300 Subject: [PATCH 3/4] v 2.0.1 add check zabbix api --- config/.env-template | 1 + config/config.py | 1 + docker/docker-compose.yaml | 2 ++ main.py | 15 +++++++-- telegram/bot.py | 3 +- telegram/message.py | 2 +- zabbix/__init__.py | 4 +-- zabbix/zabbix_api.py | 64 +++++++++++++++++--------------------- 8 files changed, 50 insertions(+), 42 deletions(-) diff --git a/config/.env-template b/config/.env-template index 5816293..cfdacf2 100755 --- a/config/.env-template +++ b/config/.env-template @@ -7,6 +7,7 @@ CFG__ZABBIX__MIN_SEVERITY=0 CFG__ZABBIX__UPD_INTERVAL=60 CFG__ZABBIX__ALERT_FAIL_COUNT=3 CFG__ZABBIX__ALERT_TREAD_ID=0 +CFG__ZABBIX__ALERT_TAG_USER=string CFG__ZABBIX__ALERT_TEXT_UP=Zabbix service UP CFG__ZABBIX__ALERT_TEXT_DOWN=Zabbix service DOWN diff --git a/config/config.py b/config/config.py index 3720822..793e476 100755 --- a/config/config.py +++ b/config/config.py @@ -51,6 +51,7 @@ class ZabbixConfig(BaseModel): upd_interval: int alert_fail_count: int alert_tread_id: int + alert_tag_user: str = "" alert_text_up: str alert_text_down: str change_state_count: int = 0 diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index b752209..89b00e9 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -12,6 +12,8 @@ services: tg-bot: image: git.sm8255082.ru/osnova/zbx-tg-bot:2.0.1 restart: always + volumes: + - ./logfile.log:/app/logfile.log depends_on: - redis environment: diff --git a/main.py b/main.py index 125ebe7..adeca18 100644 --- a/main.py +++ b/main.py @@ -1,5 +1,5 @@ import logging as log -from zabbix import get_active_problems +from zabbix import get_active_problems, check_state from config import conf, icon_dict from redis_db import ( get_all_keys, @@ -8,13 +8,24 @@ from redis_db import ( del_value, ) import asyncio -from telegram import del_message, send_message, start_bot +from telegram import del_message, send_message, start_bot, send_zabbix_api_alert async def dashboard(): active_alerts = get_active_problems() if active_alerts is None: + if check_state(False) == "DOWN": + send_state = await send_zabbix_api_alert(conf.zabbix.alert_text_down) + if send_state["status"] == 200: + conf.zabbix.api_state = "DOWN" + conf.zabbix.change_state_count = 0 return + else: + if check_state(True) == "UP": + send_state = await send_zabbix_api_alert(conf.zabbix.alert_text_up) + if send_state["status"] == 200: + conf.zabbix.api_state = "UP" + conf.zabbix.change_state_count = 0 telegram_alerts = await get_all_keys() new_alerts_id = [] diff --git a/telegram/bot.py b/telegram/bot.py index 3d911ac..a800917 100644 --- a/telegram/bot.py +++ b/telegram/bot.py @@ -2,7 +2,8 @@ from config import conf from aiogram import Bot, Dispatcher, types from aiogram.fsm.storage.memory import MemoryStorage from aiogram import F -from zabbix import event_acknowledge, event_close +from zabbix import event_close +from zabbix import event_acknowledge import logging as log tg_bot = Bot(token=conf.tgbot.token) diff --git a/telegram/message.py b/telegram/message.py index ee264da..29109c8 100644 --- a/telegram/message.py +++ b/telegram/message.py @@ -81,7 +81,7 @@ async def send_zabbix_api_alert(message): params = { "chat_id": conf.tgbot.chat_id, "message_thread_id": conf.zabbix.alert_tread_id, - "text": message, + "text": conf.zabbix.alert_tag_user + "\n" + message, } async with aiohttp.ClientSession() as session: try: diff --git a/zabbix/__init__.py b/zabbix/__init__.py index 7a4de3f..e53c8e7 100644 --- a/zabbix/__init__.py +++ b/zabbix/__init__.py @@ -1,8 +1,8 @@ -from .zabbix_api import get_active_problems, event_acknowledge, event_close - +from .zabbix_api import get_active_problems, event_close, event_acknowledge, check_state __all__ = [ "get_active_problems", "event_acknowledge", "event_close", + "check_state", ] diff --git a/zabbix/zabbix_api.py b/zabbix/zabbix_api.py index 668ed60..8e41348 100644 --- a/zabbix/zabbix_api.py +++ b/zabbix/zabbix_api.py @@ -3,45 +3,12 @@ import logging as log from pyexpat.errors import messages from zabbix_utils import ZabbixAPI -import telegram + from config import conf from datetime import datetime, timedelta -def check_state(success: bool) -> None: - if success: - if conf.zabbix.api_state == "UP": - log.info("Zabbix API is UP") - conf.zabbix.change_state_count = 0 - else: - if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count: - log.warning( - f"Zabbix API state changed to UP. Count {conf.zabbix.change_state_count}" - ) - send_result = telegram.send_zabbix_api_alert(conf.zabbix.alert_text_up) - if send_result["status"] == 200: - conf.zabbix.change_state_count = 0 - else: - conf.zabbix.change_state_count += 1 - else: - if conf.zabbix.api_state == "DOWN": - log.info("Zabbix API is DOWN") - conf.zabbix.change_state_count = 0 - else: - if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count: - log.warning( - f"Zabbix API state changed to DOWN. Count {conf.zabbix.change_state_count}" - ) - send_result = telegram.send_zabbix_api_alert( - conf.zabbix.alert_text_down - ) - if send_result["status"] == 200: - conf.zabbix.change_state_count = 0 - else: - conf.zabbix.change_state_count += 1 - - def get_active_problems() -> dict: api = ZabbixAPI(url=conf.zabbix.url, token=conf.zabbix.token) try: @@ -74,11 +41,9 @@ def get_active_problems() -> dict: event["host"] = event.pop("hosts", None)[0]["host"] events_dict[event["eventid"]] = event events_dict["event_ids"].append(event["eventid"]) - check_state(True) return events_dict except: log.warning("Get event from zabbix error") - check_state(False) def event_acknowledge(event_id: int, mute_time: int, muted_by: str): @@ -116,3 +81,30 @@ def event_close(event_id: int, closed_by: str): except: log.warning(f"Closed event {event_id} from zabbix error") return False + + +def check_state(success: bool) -> str | None: + if success: + if conf.zabbix.api_state == "UP": + log.info("Zabbix API is UP") + conf.zabbix.change_state_count = 0 + else: + if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count - 1: + log.warning( + f"Zabbix API state changed to UP. Count {conf.zabbix.change_state_count}" + ) + return "UP" + else: + conf.zabbix.change_state_count += 1 + else: + if conf.zabbix.api_state == "DOWN": + log.info("Zabbix API is DOWN") + conf.zabbix.change_state_count = 0 + else: + if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count - 1: + log.warning( + f"Zabbix API state changed to DOWN. Count {conf.zabbix.change_state_count}" + ) + return "DOWN" + else: + conf.zabbix.change_state_count += 1 From 672c02f64bd4462ed3b5d4674c16c03797146839 Mon Sep 17 00:00:00 2001 From: sergey Date: Mon, 14 Apr 2025 16:28:24 +0300 Subject: [PATCH 4/4] fix check zabbix api count --- docker/docker-compose.yaml | 1 + zabbix/zabbix_api.py | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 89b00e9..22f123f 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -26,6 +26,7 @@ services: - CFG__ZABBIX__UPD_INTERVAL=30 - CFG__ZABBIX__ALERT_FAIL_COUNT=3 - CFG__ZABBIX__ALERT_TREAD_ID=0 + - CFG__ZABBIX__ALERT_TAG_USER= - CFG__ZABBIX__ALERT_TEXT_UP=Zabbix service UP - CFG__ZABBIX__ALERT_TEXT_DOWN=Zabbix service DOWN diff --git a/zabbix/zabbix_api.py b/zabbix/zabbix_api.py index 8e41348..0f71e9a 100644 --- a/zabbix/zabbix_api.py +++ b/zabbix/zabbix_api.py @@ -89,7 +89,7 @@ def check_state(success: bool) -> str | None: log.info("Zabbix API is UP") conf.zabbix.change_state_count = 0 else: - if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count - 1: + if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count: log.warning( f"Zabbix API state changed to UP. Count {conf.zabbix.change_state_count}" ) @@ -101,7 +101,7 @@ def check_state(success: bool) -> str | None: log.info("Zabbix API is DOWN") conf.zabbix.change_state_count = 0 else: - if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count - 1: + if conf.zabbix.change_state_count == conf.zabbix.alert_fail_count: log.warning( f"Zabbix API state changed to DOWN. Count {conf.zabbix.change_state_count}" )