12.03
This commit is contained in:
parent
fc1e34e727
commit
273b972b49
|
@ -1,7 +1,8 @@
|
|||
from .config import conf, STATIC_DIR
|
||||
from .config import conf, STATIC_DIR, icon_dict
|
||||
|
||||
|
||||
__all__ = [
|
||||
"conf",
|
||||
STATIC_DIR,
|
||||
icon_dict,
|
||||
]
|
||||
|
|
|
@ -12,6 +12,15 @@ import logging
|
|||
BASE_DIR = Path(__file__).parent.parent
|
||||
TEMPLATES_DIR = BASE_DIR / "web" / "templates"
|
||||
STATIC_DIR = BASE_DIR / "web" / "static"
|
||||
icon_dict = {
|
||||
"0": "",
|
||||
"1": "🟦",
|
||||
"2": "🟨",
|
||||
"3": "🟧",
|
||||
"4": "🟥",
|
||||
"5": "🟫",
|
||||
"10": "✅",
|
||||
}
|
||||
|
||||
|
||||
class LogConfig(BaseModel):
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
FROM python:3.12-slim
|
||||
WORKDIR /app
|
||||
ADD config /app/config
|
||||
ADD redis_db /app/redis_db
|
||||
ADD telegram /app/telegram
|
||||
ADD zabbix /app/zabbix
|
||||
ADD main.py /app/main.py
|
||||
ADD pyproject.toml /app/pyproject.toml
|
||||
ADD uv.lock /app/uv.lock
|
||||
RUN pip install --upgrade pip
|
||||
RUN pip install uv
|
||||
RUN uv sync --no-dev
|
||||
CMD ["uv", "run", "main.py"]
|
|
@ -0,0 +1,34 @@
|
|||
version: '3.3'
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:latest
|
||||
restart: always
|
||||
volumes:
|
||||
- ./local_redis_file/data:/data
|
||||
command: [redis-server, --protected-mode yes, --port 6379, --requirepass, P@ssw0rd!]
|
||||
|
||||
tg-bot:
|
||||
image: git.sm8255082.ru/osnova/zbx-tg-bot:1.0.0
|
||||
restart: always
|
||||
depends_on:
|
||||
- redis
|
||||
ports:
|
||||
- "8000:8000"
|
||||
environment:
|
||||
- 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__TGBOT__TOKEN=string
|
||||
- CFG__TGBOT__CHAT_ID=000000
|
||||
- CFG__TGBOT__TREAD_ID=0
|
||||
|
||||
- CFG__REDIS__HOST=redis
|
||||
- CFG__REDIS__PORT=6379
|
||||
- CFG__REDIS__PWD=P@ssw0rd!
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
version: '3.3'
|
||||
|
||||
services:
|
||||
redis:
|
||||
image: redis:latest
|
||||
restart: always
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- ./local_redis_file/data:/data
|
||||
#command: ["redis-server", --port 6379]
|
||||
command: [redis-server, --protected-mode yes, --port 6379, --requirepass, P@ssw0rd!]
|
52
main.py
52
main.py
|
@ -1,21 +1,61 @@
|
|||
import logging as log
|
||||
from zabbix import get_active_problems
|
||||
from config import conf
|
||||
from config import conf, icon_dict
|
||||
from time import sleep
|
||||
from redis_db import (
|
||||
get_all_keys,
|
||||
get_value,
|
||||
set_value,
|
||||
del_value,
|
||||
)
|
||||
import asyncio
|
||||
from telegram import del_message, send_message
|
||||
|
||||
|
||||
def main_loop():
|
||||
async def main_loop():
|
||||
active_alerts = get_active_problems()
|
||||
for i in active_alerts:
|
||||
print(i)
|
||||
print(len(active_alerts))
|
||||
telegram_alerts = await get_all_keys()
|
||||
|
||||
new_alerts_id = []
|
||||
closed_alerts_id = []
|
||||
|
||||
for active_alert in active_alerts["event_ids"]:
|
||||
if active_alert not in telegram_alerts:
|
||||
new_alerts_id.append(active_alert)
|
||||
|
||||
for telegram_alert in telegram_alerts:
|
||||
if telegram_alert not in active_alerts["event_ids"]:
|
||||
closed_alerts_id.append(telegram_alert)
|
||||
|
||||
log.info("new " + str(new_alerts_id))
|
||||
log.info("closed " + str(closed_alerts_id))
|
||||
|
||||
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]['name']}"
|
||||
)
|
||||
msg_id = await send_message(message)
|
||||
if msg_id["status"] == 200:
|
||||
await set_value(key=new_alert, value=msg_id["msg_id"])
|
||||
|
||||
for closed_alert in closed_alerts_id:
|
||||
msg_id = await get_value(closed_alert)
|
||||
if msg_id:
|
||||
resp = await del_message(int(msg_id))
|
||||
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)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
log.info("Starting app")
|
||||
try:
|
||||
while True:
|
||||
main_loop()
|
||||
asyncio.run(main_loop())
|
||||
sleep(conf.zabbix.upd_interval)
|
||||
except KeyboardInterrupt:
|
||||
log.info("Manual app stopped")
|
||||
|
|
|
@ -3,6 +3,9 @@ from .crud import (
|
|||
set_value,
|
||||
ping,
|
||||
pop_value,
|
||||
get_all,
|
||||
get_all_keys,
|
||||
del_value,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
|
@ -10,4 +13,7 @@ __all__ = [
|
|||
"set_value",
|
||||
"ping",
|
||||
"pop_value",
|
||||
"get_all",
|
||||
"get_all_keys",
|
||||
"del_value",
|
||||
]
|
||||
|
|
|
@ -31,3 +31,29 @@ async def pop_value(key):
|
|||
value = await redis_connect.client.getdel(key)
|
||||
log.info("Get and delete %s = %s", key, value)
|
||||
return value
|
||||
|
||||
|
||||
async def del_value(key):
|
||||
async with RedisManager() as redis_connect:
|
||||
if redis_connect:
|
||||
value = await redis_connect.client.delete(key)
|
||||
log.info("Delete %s = %s", key, value)
|
||||
|
||||
|
||||
async def get_all():
|
||||
async with RedisManager() as redis_connect:
|
||||
if redis_connect:
|
||||
all_data = {}
|
||||
async for key in redis_connect.client.scan_iter():
|
||||
value = await redis_connect.client.get(key)
|
||||
all_data[key] = value if value else None
|
||||
return all_data
|
||||
|
||||
|
||||
async def get_all_keys():
|
||||
async with RedisManager() as redis_connect:
|
||||
if redis_connect:
|
||||
all_keys = []
|
||||
async for key in redis_connect.client.scan_iter():
|
||||
all_keys.append(key)
|
||||
return all_keys
|
||||
|
|
|
@ -10,6 +10,7 @@ class RedisManager:
|
|||
self.connect_params = {
|
||||
"host": conf.redis.host,
|
||||
"port": conf.redis.port,
|
||||
"decode_responses": True,
|
||||
}
|
||||
if conf.redis.pwd:
|
||||
self.connect_params["password"] = conf.redis.pwd
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
from .message import (
|
||||
send_message,
|
||||
del_message,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"send_message",
|
||||
"del_message",
|
||||
]
|
|
@ -6,8 +6,7 @@ from config import conf
|
|||
|
||||
async def send_message(
|
||||
message: str,
|
||||
|
||||
) -> dict | None:
|
||||
) -> dict:
|
||||
url = f"https://api.telegram.org/bot{conf.tgbot.token}/sendMessage"
|
||||
params = {
|
||||
"chat_id": conf.tgbot.chat_id,
|
||||
|
@ -16,37 +15,52 @@ async def send_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}")
|
||||
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,
|
||||
"msg_id": resp["result"]["message_id"],
|
||||
}
|
||||
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}
|
||||
|
||||
|
||||
async def del_message(
|
||||
message_id: int,
|
||||
) -> dict | None:
|
||||
) -> dict:
|
||||
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}")
|
||||
try:
|
||||
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"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}
|
||||
|
|
|
@ -5,7 +5,7 @@ from zabbix_utils import ZabbixAPI
|
|||
from config import conf
|
||||
|
||||
|
||||
def get_active_problems():
|
||||
def get_active_problems() -> dict:
|
||||
api = ZabbixAPI(url=conf.zabbix.url, token=conf.zabbix.token)
|
||||
try:
|
||||
problems = api.problem.get(
|
||||
|
@ -32,8 +32,11 @@ def get_active_problems():
|
|||
"severity",
|
||||
],
|
||||
)
|
||||
events_dict = {"event_ids": []}
|
||||
for event in events:
|
||||
event["host"] = event.pop("hosts", None)[0]["host"]
|
||||
return events
|
||||
events_dict[event["eventid"]] = event
|
||||
events_dict["event_ids"].append(event["eventid"])
|
||||
return events_dict
|
||||
except:
|
||||
log.warning("Get event from zabbix error")
|
||||
|
|
Loading…
Reference in New Issue