feat: Borg-Diagnose und manuellen Backup-Start ergaenzen

This commit is contained in:
sascha 2026-08-05 14:01:37 +02:00
parent 3fcbc8268f
commit c019d2dcec

55
app.py
View file

@ -546,6 +546,61 @@ async def backup_status(_=Depends(_verify)):
return await _collect_backup_status() return await _collect_backup_status()
@app.get("/backup/diagnose/{hostname}")
async def backup_diagnose(hostname: str, _=Depends(_verify)):
"""Safe Borgmatic timer/service diagnostics without exposing backup secrets."""
host = await asyncio.to_thread(_find_inventory_host, hostname)
if not host or host["name"].startswith("node"):
return JSONResponse({"error": "inventory host not found"}, status_code=404)
command = """echo __TIMER_ENABLED__
sudo -n systemctl is-enabled borg-backup.timer 2>&1 || true
echo __TIMER_ACTIVE__
sudo -n systemctl is-active borg-backup.timer 2>&1 || true
echo __TIMER_SCHEDULE__
sudo -n systemctl list-timers borg-backup.timer --all --no-pager 2>&1 || true
echo __SERVICE_STATE__
sudo -n systemctl show borg-backup.service -p ActiveState -p SubState -p Result -p ExecMainStatus --no-pager 2>&1 || true
echo __RECENT_LOGS__
sudo -n journalctl -u borg-backup.service --since '2 days ago' -n 120 --no-pager 2>&1 || true
echo __LATEST_ARCHIVE__
timeout 50s sudo -n borgmatic list --last 1 --json 2>&1 || true
"""
rc, out, err = await asyncio.to_thread(
_ssh, f'{host["user"]}@{host["ip"]}', command, 75
)
return {
"hostname": host["name"], "ip": host["ip"], "user": host["user"],
"rc": rc, "output": out[-30000:], "stderr": err[-2000:],
}
@app.post("/backup/run/{hostname}")
async def backup_run(hostname: str, _=Depends(_verify)):
"""Start one inventory host Borgmatic service asynchronously."""
host = await asyncio.to_thread(_find_inventory_host, hostname)
if not host or host["name"].startswith("node"):
return JSONResponse({"error": "inventory host not found"}, status_code=404)
command = (
"sudo -n systemctl reset-failed borg-backup.service 2>/dev/null || true; "
"sudo -n systemctl start --no-block borg-backup.service; sleep 2; "
"sudo -n systemctl show borg-backup.service -p ActiveState -p SubState -p Result --no-pager"
)
rc, out, err = await asyncio.to_thread(
_ssh, f'{host["user"]}@{host["ip"]}', command, 20
)
_audit(f"/backup/run/{hostname}", "POST", 202 if rc == 0 else 500, f"rc={rc}")
if rc != 0:
return JSONResponse(
{"error": "backup start failed", "hostname": hostname,
"stdout": out[-2000:], "stderr": err[-2000:]},
status_code=500,
)
return JSONResponse(
{"status": "started", "hostname": hostname, "detail": out.strip()},
status_code=202,
)
async def _collect_disk_usage(concurrency: int = 10) -> dict: async def _collect_disk_usage(concurrency: int = 10) -> dict:
semaphore = asyncio.Semaphore(concurrency) semaphore = asyncio.Semaphore(concurrency)