#!/usr/bin/env python3 """Beszel Webhook Receiver — Cria tarefas Desk CRM a partir de alertas Beszel.""" import json, os, sys, logging from http.server import HTTPServer, BaseHTTPRequestHandler from datetime import datetime import pymysql PORT = int(sys.argv[sys.argv.index("--port") + 1]) if "--port" in sys.argv else 8650 DB_CONFIG = {"host": "server.descomplicar.pt", "port": 3306, "user": "ealmeida_desk24", "password": "9qPRdCGGqM4o", "database": "ealmeida_desk24", "charset": "utf8mb4"} # Configuração Desk CRM PROJECT_ID = 65 # DES Stack Workflow MILESTONE_ID = 355 # Sistemas de Apoio (Tecnologia) ASSIGNEE_STAFF_ID = 28 # Izito CREATOR_STAFF_ID = 25 # Claude/AIkTop PRIORITY = 3 # Alta LOG = "/root/logs/beszel-webhook.log" os.makedirs(os.path.dirname(LOG), exist_ok=True) logging.basicConfig(level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", handlers=[logging.FileHandler(LOG, encoding="utf-8"), logging.StreamHandler()]) log = logging.getLogger("beszel-webhook") def get_db(): return pymysql.connect(**DB_CONFIG, cursorclass=pymysql.cursors.DictCursor) def tarefa_existe(cur, padrao): """Verifica se já existe tarefa aberta com o padrão indicado.""" cur.execute( "SELECT id FROM tbltasks WHERE name LIKE %s AND status NOT IN (5,6) AND rel_type='project' AND rel_id=%s LIMIT 1", (padrao, PROJECT_ID) ) return cur.fetchone() def criar_tarefa(cur, nome, descricao): """Cria tarefa Desk CRM no projecto 65, milestone 355, atribuída a Izito.""" now = datetime.now().strftime("%Y-%m-%d %H:%M:%S") cur.execute( """INSERT INTO tbltasks (name, description, priority, status, rel_type, rel_id, milestone, addedfrom, startdate, dateadded) VALUES (%s, %s, %s, 1, %s, %s, %s, %s, %s, %s)""", (nome, descricao, PRIORITY, "project", PROJECT_ID, MILESTONE_ID, CREATOR_STAFF_ID, now[:10], now) ) tid = cur.lastrowid cur.execute( "INSERT INTO tbltask_assigned (taskid, staffid, assigned_from) VALUES (%s, %s, 0)", (tid, ASSIGNEE_STAFF_ID) ) log.info(f"Tarefa #{tid} criada — {nome}") return tid def fechar_tarefa(cur, tid, nota): """Fecha tarefa (status 5 = Terminado).""" cur.execute("UPDATE tbltasks SET status=5, datefinished=NOW() WHERE id=%s", (tid,)) log.info(f"Tarefa #{tid} fechada: {nota}") class Handler(BaseHTTPRequestHandler): def do_POST(self): if self.path != "/beszel-alert": self.send_response(404) self.end_headers() return body = self.rfile.read(int(self.headers.get("Content-Type-Length", 0))) try: data = json.loads(body) except Exception: self.send_response(400) self.end_headers() return titulo = data.get("title", "") mensagem = data.get("message", "") log.info(f"Webhook: {titulo} — {mensagem}") is_down = "down" in (mensagem + titulo).lower() is_up = "up" in mensagem.lower() or "recovered" in mensagem.lower() # Extrair nome do sistema sname = data.get("system", "") or data.get("name", "") or data.get("host", "") if not sname: parts = mensagem.split(":") if len(parts) > 1: sname = parts[1].strip().split("(")[0].strip() try: db = get_db() cur = db.cursor() if is_down and sname: if not tarefa_existe(cur, f"[MONIT] {sname}%"): criar_tarefa( cur, f"[MONIT] {sname} — sistema DOWN", f"
Beszel — {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
" f"{mensagem}
" ) elif is_up and sname: existente = tarefa_existe(cur, f"[MONIT] {sname}%") if existente: fechar_tarefa(cur, existente["id"], f"{sname} voltou ao normal") db.commit() cur.close() db.close() except Exception as e: log.error(f"Erro Desk CRM: {e}") self.send_response(200) self.send_header("Content-Type", "application/json") self.end_headers() self.wfile.write(b'{"status":"ok"}') def log_message(self, fmt, *args): log.info(f"{self.client_address[0]} - {fmt % args}") if __name__ == "__main__": srv = HTTPServer(("0.0.0.0", PORT), Handler) log.info(f"Beszel Webhook Receiver a escutar na porta {PORT}") srv.serve_forever()