diff --git a/config/.env-template b/config/.env-template index 178b345..8b59671 100755 --- a/config/.env-template +++ b/config/.env-template @@ -4,6 +4,7 @@ CFG__LOG__LEVEL_TO_FILE=30 CFG__ZABBIX__URL=https://example.com CFG__ZABBIX__TOKEN=string CFG__ZABBIX__MIN_SEVERITY=0 +CFG__ZABBIX__UPD_INTERVAL=60 CFG__TGBOT__TOKEN=string CFG__TGBOT__CHAT_ID=00000000 diff --git a/config/config.py b/config/config.py index e970d18..4841705 100755 --- a/config/config.py +++ b/config/config.py @@ -34,10 +34,13 @@ class TelegramBotConfig(BaseModel): chat_id: int tread_id: int + class ZabbixConfig(BaseModel): url: str token: str min_severity: int + upd_interval: int + class Settings(BaseSettings): model_config = SettingsConfigDict( @@ -55,7 +58,6 @@ class Settings(BaseSettings): zabbix: ZabbixConfig - conf = Settings() diff --git a/main.py b/main.py index 5d2e541..9bb5fe9 100644 --- a/main.py +++ b/main.py @@ -1,11 +1,22 @@ import logging as log +from zabbix import get_active_problems from config import conf +from time import sleep -def main(): - print("Hello from zbx-tg-bot!") + +def main_loop(): + active_alerts = get_active_problems() + for i in active_alerts: + print(i) + print(len(active_alerts)) if __name__ == "__main__": log.info("Starting app") - main() - log.info("App stopped") \ No newline at end of file + try: + while True: + main_loop() + sleep(conf.zabbix.upd_interval) + except KeyboardInterrupt: + log.info("Manual app stopped") + log.info("App stopped") diff --git a/redis_db/__init__.py b/redis_db/__init__.py new file mode 100644 index 0000000..54cc2e2 --- /dev/null +++ b/redis_db/__init__.py @@ -0,0 +1,13 @@ +from .crud import ( + get_value, + set_value, + ping, + pop_value, +) + +__all__ = [ + "get_value", + "set_value", + "ping", + "pop_value", +] diff --git a/redis_db/crud.py b/redis_db/crud.py new file mode 100644 index 0000000..bd76476 --- /dev/null +++ b/redis_db/crud.py @@ -0,0 +1,33 @@ +import logging as log +from .r_helper import RedisManager + + +async def ping(): + async with RedisManager() as redis_connect: + if redis_connect: + result = await redis_connect.client.ping() + log.info("Ping - %s", result) + return result + + +async def set_value(key, value): + async with RedisManager() as redis_connect: + if redis_connect: + await redis_connect.client.set(key, value) + log.info("Set %s = %s", key, value) + + +async def get_value(key): + async with RedisManager() as redis_connect: + if redis_connect: + value = await redis_connect.client.get(key) + log.info("Get %s = %s", key, value) + return value + + +async def pop_value(key): + async with RedisManager() as redis_connect: + if redis_connect: + value = await redis_connect.client.getdel(key) + log.info("Get and delete %s = %s", key, value) + return value diff --git a/redis_db/r_helper.py b/redis_db/r_helper.py new file mode 100644 index 0000000..9442a6c --- /dev/null +++ b/redis_db/r_helper.py @@ -0,0 +1,30 @@ +from redis.asyncio import Redis +from redis import ConnectionError +from config import conf +import logging as log + + +class RedisManager: + def __init__(self): + self.client = None + self.connect_params = { + "host": conf.redis.host, + "port": conf.redis.port, + } + if conf.redis.pwd: + self.connect_params["password"] = conf.redis.pwd + + async def __aenter__(self): + self.client = Redis(**self.connect_params) + try: + await self.client.ping() + log.info("connected to Redis") + return self + except ConnectionError: + log.warning("failed to connect to Redis") + self.client = None + + async def __aexit__(self, exc_type, exc_val, exc_tb): + if self.client: + await self.client.close() + log.info("closed connection to Redis") diff --git a/zabbix.py b/telegram/__init__.py similarity index 100% rename from zabbix.py rename to telegram/__init__.py diff --git a/telegram/message.py b/telegram/message.py new file mode 100644 index 0000000..946f7b7 --- /dev/null +++ b/telegram/message.py @@ -0,0 +1,52 @@ +import logging as log + +import aiohttp +from config import conf + + +async def send_message( + message: str, + +) -> dict | None: + url = f"https://api.telegram.org/bot{conf.tgbot.token}/sendMessage" + params = { + "chat_id": conf.tgbot.chat_id, + "message_thread_id": conf.tgbot.tread_id, + "text": message, + } + + async with aiohttp.ClientSession() as session: + 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, + "msg_id": resp["result"]["message_id"], + } + log.warning(f"Message not send. Response status: {response.status}") + + +async def del_message( + message_id: int, +) -> dict | None: + url = f"https://api.telegram.org/bot{conf.tgbot.token}/deleteMessage" + async with aiohttp.ClientSession() as session: + async with session.post( + url, + json={ + "chat_id": conf.tgbot.chat_id, + "message_id": message_id, + }, + ) as response: + if response.status == 200: + log.info(f"Message ID {message_id} deleted") + return { + "status": response.status, + } + else: + log.warning(f"Response status: {response.status}") diff --git a/zabbix/__init__.py b/zabbix/__init__.py new file mode 100644 index 0000000..7c9de56 --- /dev/null +++ b/zabbix/__init__.py @@ -0,0 +1,6 @@ +from .zabbix_api import get_active_problems + + +__all__ = [ + "get_active_problems", +] diff --git a/zabbix/zabbix_api.py b/zabbix/zabbix_api.py new file mode 100644 index 0000000..aa747a8 --- /dev/null +++ b/zabbix/zabbix_api.py @@ -0,0 +1,39 @@ +import logging as log + +from zabbix_utils import ZabbixAPI + +from config import conf + + +def get_active_problems(): + api = ZabbixAPI(url=conf.zabbix.url, token=conf.zabbix.token) + try: + problems = api.problem.get( + output=[ + "eventid", + "suppressed", + "severity", + ], + ) + event_ids = [] + for problem in problems: + if ( + problem["suppressed"] == "0" + and int(problem["severity"]) >= conf.zabbix.min_severity + ): + event_ids.append(problem["eventid"]) + + events = api.event.get( + selectHosts=["host"], + eventids=event_ids, + output=[ + "eventid", + "name", + "severity", + ], + ) + for event in events: + event["host"] = event.pop("hosts", None)[0]["host"] + return events + except: + log.warning("Get event from zabbix error")