Add linux/webhook.py
This commit is contained in:
@@ -0,0 +1,87 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Webhook-Empfänger für Lexware-Dump-Benachrichtigungen vom Windows-Server.
|
||||||
|
|
||||||
|
POST /restore?db=f1 → nur f1 wiederherstellen
|
||||||
|
POST /restore → alle DBs prüfen und bei Bedarf wiederherstellen
|
||||||
|
GET /health → Liveness-Check
|
||||||
|
"""
|
||||||
|
|
||||||
|
import http.server
|
||||||
|
import subprocess
|
||||||
|
import threading
|
||||||
|
import urllib.parse
|
||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
PORT = 9055
|
||||||
|
RESTORE_SCRIPT = "/opt/lexware-dumps/restore-latest.sh"
|
||||||
|
LOG_FILE = "/var/log/lexware-restore.log"
|
||||||
|
VALID_DBS = {"f1", "f2", "lexkonto", "lexkk", "rk", "lxoffice", "lx", "lxcatalog"}
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO,
|
||||||
|
format="%(asctime)s [webhook] %(message)s",
|
||||||
|
datefmt="%Y-%m-%d %H:%M:%S",
|
||||||
|
handlers=[
|
||||||
|
logging.FileHandler(LOG_FILE),
|
||||||
|
logging.StreamHandler(sys.stdout),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def run_restore(db: str | None):
|
||||||
|
env = os.environ.copy()
|
||||||
|
cmd = [RESTORE_SCRIPT]
|
||||||
|
if db:
|
||||||
|
env["RESTORE_DB"] = db
|
||||||
|
logging.info(f"Starte Restore: db={db or 'alle'}")
|
||||||
|
result = subprocess.run(cmd, env=env, capture_output=True, text=True)
|
||||||
|
if result.stdout:
|
||||||
|
for line in result.stdout.strip().splitlines():
|
||||||
|
logging.info(line)
|
||||||
|
if result.returncode not in (0, 1):
|
||||||
|
logging.error(f"Restore-Skript exit {result.returncode}")
|
||||||
|
|
||||||
|
|
||||||
|
class WebhookHandler(http.server.BaseHTTPRequestHandler):
|
||||||
|
def log_message(self, fmt, *args):
|
||||||
|
logging.info(f"{self.address_string()} {fmt % args}")
|
||||||
|
|
||||||
|
def do_POST(self):
|
||||||
|
parsed = urllib.parse.urlparse(self.path)
|
||||||
|
params = urllib.parse.parse_qs(parsed.query)
|
||||||
|
|
||||||
|
if parsed.path != "/restore":
|
||||||
|
self._respond(404, "Not found")
|
||||||
|
return
|
||||||
|
|
||||||
|
db = params.get("db", [None])[0]
|
||||||
|
if db and db not in VALID_DBS:
|
||||||
|
self._respond(400, f"Unbekannte Datenbank: {db}")
|
||||||
|
return
|
||||||
|
|
||||||
|
self._respond(200, f"OK: Restore gestartet (db={db or 'alle'})")
|
||||||
|
# Restore asynchron starten damit der Webhook sofort antwortet
|
||||||
|
threading.Thread(target=run_restore, args=(db,), daemon=True).start()
|
||||||
|
|
||||||
|
def do_GET(self):
|
||||||
|
if self.path == "/health":
|
||||||
|
self._respond(200, "OK")
|
||||||
|
else:
|
||||||
|
self._respond(404, "Not found")
|
||||||
|
|
||||||
|
def _respond(self, code: int, body: str):
|
||||||
|
data = body.encode()
|
||||||
|
self.send_response(code)
|
||||||
|
self.send_header("Content-Type", "text/plain")
|
||||||
|
self.send_header("Content-Length", str(len(data)))
|
||||||
|
self.end_headers()
|
||||||
|
self.wfile.write(data)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
server = http.server.ThreadingHTTPServer(("0.0.0.0", PORT), WebhookHandler)
|
||||||
|
logging.info(f"Webhook-Server läuft auf Port {PORT}")
|
||||||
|
server.serve_forever()
|
||||||
Reference in New Issue
Block a user