Compare commits
No commits in common. "main" and "dev-2.0.0" have entirely different histories.
|
@ -28,8 +28,3 @@
|
|||
10. Адрес для подключения к redis
|
||||
11. Порт для подключения к redis
|
||||
12. Пароль для подключения к redis (если нужен)
|
||||
|
||||
|
||||
UPD
|
||||
Добавлена проверка доступности апи заббикса и алерт в телегу, если не доступен.
|
||||
Добавлено изменнеие алерта на произвольный текст, если сообщение нельзя удалить из-за срока давности.
|
||||
|
|
|
@ -5,16 +5,10 @@ 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__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
|
||||
|
||||
CFG__TGBOT__TOKEN=string
|
||||
CFG__TGBOT__CHAT_ID=00000000
|
||||
CFG__TGBOT__TREAD_ID=0
|
||||
CFG__TGBOT__DELETE_MSG=string
|
||||
|
||||
CFG__REDIS__HOST=localhost
|
||||
CFG__REDIS__PORT=6379
|
||||
|
|
|
@ -42,7 +42,6 @@ class TelegramBotConfig(BaseModel):
|
|||
token: str
|
||||
chat_id: int
|
||||
tread_id: int
|
||||
delete_msg: str
|
||||
|
||||
|
||||
class ZabbixConfig(BaseModel):
|
||||
|
@ -50,13 +49,6 @@ class ZabbixConfig(BaseModel):
|
|||
token: str
|
||||
min_severity: int
|
||||
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
|
||||
api_state: str = "UP"
|
||||
|
||||
|
||||
class Settings(BaseSettings):
|
||||
|
|
|
@ -10,30 +10,22 @@ services:
|
|||
command: [redis-server, --protected-mode yes, --port 6379, --requirepass, P@ssw0rd!]
|
||||
|
||||
tg-bot:
|
||||
image: git.sm8255082.ru/osnova/zbx-tg-bot:2.0.1
|
||||
image: git.sm8255082.ru/osnova/zbx-tg-bot:2.0.0
|
||||
restart: always
|
||||
volumes:
|
||||
- ./logfile.log:/app/logfile.log
|
||||
depends_on:
|
||||
- redis
|
||||
environment:
|
||||
- CFG__LOG__LEVEL=30
|
||||
- CFG__LOG__LEVEL_TO_FILE=30
|
||||
- OAA_CFG__LOG__LEVEL=30
|
||||
- OAA_CFG__LOG__LEVEL_TO_FILE=30
|
||||
|
||||
- CFG__ZABBIX__URL=https://zabbix.example.com
|
||||
- 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_TAG_USER=
|
||||
- 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
|
||||
- CFG__TGBOT__TREAD_ID=0
|
||||
- CFG__TGBOT__DELETE_MSG=Deleted
|
||||
|
||||
- CFG__REDIS__HOST=redis
|
||||
- CFG__REDIS__PORT=6379
|
||||
|
|
31
main.py
31
main.py
|
@ -1,5 +1,5 @@
|
|||
import logging as log
|
||||
from zabbix import get_active_problems, check_state
|
||||
from zabbix import get_active_problems
|
||||
from config import conf, icon_dict
|
||||
from redis_db import (
|
||||
get_all_keys,
|
||||
|
@ -8,30 +8,13 @@ from redis_db import (
|
|||
del_value,
|
||||
)
|
||||
import asyncio
|
||||
from telegram import (
|
||||
del_message,
|
||||
send_message,
|
||||
start_bot,
|
||||
send_zabbix_api_alert,
|
||||
edit_message,
|
||||
)
|
||||
from telegram import del_message, send_message, start_bot
|
||||
|
||||
|
||||
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 = []
|
||||
|
@ -51,7 +34,7 @@ async def dashboard():
|
|||
for new_alert in new_alerts_id:
|
||||
message = (
|
||||
icon_dict[active_alerts[new_alert]["severity"]]
|
||||
+ f" {active_alerts[new_alert]['host']}\n"
|
||||
+ f"{active_alerts[new_alert]['host']}\n"
|
||||
+ f"{active_alerts[new_alert]['name']}"
|
||||
)
|
||||
msg_id = await send_message(message=message, event_id=new_alert)
|
||||
|
@ -65,12 +48,8 @@ async def dashboard():
|
|||
if resp["status"] == 200:
|
||||
await del_value(closed_alert)
|
||||
if resp["status"] == 400:
|
||||
resp = await edit_message(int(msg_id), conf.tgbot.delete_msg)
|
||||
if resp["status"] == 200:
|
||||
await del_value(closed_alert)
|
||||
if resp["status"] == 400:
|
||||
log.warning(f"remove olg message {msg_id} from reddis")
|
||||
await del_value(closed_alert)
|
||||
log.warning(f"remove olg message {msg_id} from reddis")
|
||||
await del_value(closed_alert)
|
||||
|
||||
|
||||
async def dashboard_loop():
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[project]
|
||||
name = "zbx-tg-bot"
|
||||
version = "2.0.1"
|
||||
version = "2.0.0"
|
||||
description = "telegram bot for telegram-zabbix dashboard"
|
||||
requires-python = ">=3.13"
|
||||
dependencies = [
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
from .message import (
|
||||
send_message,
|
||||
edit_message,
|
||||
del_message,
|
||||
send_zabbix_api_alert,
|
||||
)
|
||||
from .bot import start_bot
|
||||
|
||||
__all__ = [
|
||||
"send_message",
|
||||
"edit_message",
|
||||
"del_message",
|
||||
"start_bot",
|
||||
"send_zabbix_api_alert",
|
||||
]
|
||||
|
|
|
@ -2,8 +2,7 @@ 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_close
|
||||
from zabbix import event_acknowledge
|
||||
from zabbix import event_acknowledge, event_close
|
||||
import logging as log
|
||||
|
||||
tg_bot = Bot(token=conf.tgbot.token)
|
||||
|
|
|
@ -45,35 +45,6 @@ async def send_message(message: str, event_id: int) -> dict:
|
|||
return {"status": e}
|
||||
|
||||
|
||||
async def edit_message(message_id: int, 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": 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 edit. 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:
|
||||
|
@ -96,36 +67,9 @@ 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": conf.zabbix.alert_tag_user + "\n" + 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}
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
from .zabbix_api import get_active_problems, event_close, event_acknowledge, check_state
|
||||
from .zabbix_api import get_active_problems, event_acknowledge, event_close
|
||||
|
||||
|
||||
__all__ = [
|
||||
"get_active_problems",
|
||||
"event_acknowledge",
|
||||
"event_close",
|
||||
"check_state",
|
||||
]
|
||||
|
|
|
@ -3,15 +3,14 @@ import logging as log
|
|||
from pyexpat.errors import messages
|
||||
from zabbix_utils import ZabbixAPI
|
||||
|
||||
|
||||
from config import conf
|
||||
|
||||
from datetime import datetime, timedelta
|
||||
|
||||
|
||||
def get_active_problems() -> dict:
|
||||
api = ZabbixAPI(url=conf.zabbix.url, token=conf.zabbix.token)
|
||||
try:
|
||||
api = ZabbixAPI(url=conf.zabbix.url, token=conf.zabbix.token)
|
||||
problems = api.problem.get(
|
||||
output=[
|
||||
"eventid",
|
||||
|
@ -28,7 +27,7 @@ def get_active_problems() -> dict:
|
|||
event_ids.append(problem["eventid"])
|
||||
|
||||
events = api.event.get(
|
||||
selectHosts=["name"],
|
||||
selectHosts=["host"],
|
||||
eventids=event_ids,
|
||||
output=[
|
||||
"eventid",
|
||||
|
@ -38,7 +37,7 @@ def get_active_problems() -> dict:
|
|||
)
|
||||
events_dict = {"event_ids": []}
|
||||
for event in events:
|
||||
event["host"] = event.pop("hosts", None)[0]["name"]
|
||||
event["host"] = event.pop("hosts", None)[0]["host"]
|
||||
events_dict[event["eventid"]] = event
|
||||
events_dict["event_ids"].append(event["eventid"])
|
||||
return events_dict
|
||||
|
@ -81,30 +80,3 @@ 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:
|
||||
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:
|
||||
log.warning(
|
||||
f"Zabbix API state changed to DOWN. Count {conf.zabbix.change_state_count}"
|
||||
)
|
||||
return "DOWN"
|
||||
else:
|
||||
conf.zabbix.change_state_count += 1
|
||||
|
|
Loading…
Reference in New Issue