11.03
This commit is contained in:
		
							parent
							
								
									db52020fa3
								
							
						
					
					
						commit
						fc1e34e727
					
				| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										19
									
								
								main.py
								
								
								
								
							
							
						
						
									
										19
									
								
								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")
 | 
			
		||||
    try:
 | 
			
		||||
        while True:
 | 
			
		||||
            main_loop()
 | 
			
		||||
            sleep(conf.zabbix.upd_interval)
 | 
			
		||||
    except KeyboardInterrupt:
 | 
			
		||||
        log.info("Manual app stopped")
 | 
			
		||||
    log.info("App stopped")
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,13 @@
 | 
			
		|||
from .crud import (
 | 
			
		||||
    get_value,
 | 
			
		||||
    set_value,
 | 
			
		||||
    ping,
 | 
			
		||||
    pop_value,
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    "get_value",
 | 
			
		||||
    "set_value",
 | 
			
		||||
    "ping",
 | 
			
		||||
    "pop_value",
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -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
 | 
			
		||||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
| 
						 | 
				
			
			@ -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}")
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,6 @@
 | 
			
		|||
from .zabbix_api import get_active_problems
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
__all__ = [
 | 
			
		||||
    "get_active_problems",
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -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")
 | 
			
		||||
		Loading…
	
		Reference in New Issue