This commit is contained in:
2026-01-28 09:51:46 +01:00
parent e8c322145a
commit 7ebe32edc0
22 changed files with 132 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
KB_MYSQL_HOST=192.168.1.50
KB_MYSQL_PORT=3306
KB_MYSQL_USER=root
KB_MYSQL_PASSWORD=Vlado9674+
KB_MYSQL_DB=kanboard
KB_BACKUP_DIR=U:\MySQLBackup\Kanboard
KB_KEEP_DAYS=30
+124
View File
@@ -0,0 +1,124 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import gzip
import shutil
import subprocess
from datetime import datetime, timedelta
from pathlib import Path
PROJECT_ROOT = Path(__file__).resolve().parent.parent
MYSQLDUMP = PROJECT_ROOT / "bin" / "mysqldump.exe"
def load_dotenv(dotenv_path: Path) -> None:
if not dotenv_path.exists():
return
for line in dotenv_path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
k, v = line.split("=", 1)
k = k.strip()
v = v.strip().strip('"').strip("'")
os.environ.setdefault(k, v)
def require_env(name: str) -> str:
v = os.getenv(name)
if not v:
raise SystemExit(f"Chybí proměnná {name} (dej ji do .env nebo env).")
return v
def run(cmd: list[str], *, cwd: Path | None = None) -> None:
# pro ladění si můžeš odkomentovat print(cmd)
p = subprocess.run(cmd, cwd=str(cwd) if cwd else None)
if p.returncode != 0:
raise SystemExit(f"Příkaz selhal (exit={p.returncode}): {' '.join(cmd)}")
def main() -> None:
here = Path(__file__).resolve().parent
load_dotenv(here / ".env")
host = require_env("KB_MYSQL_HOST")
port = require_env("KB_MYSQL_PORT")
user = require_env("KB_MYSQL_USER")
password = require_env("KB_MYSQL_PASSWORD")
db = require_env("KB_MYSQL_DB")
backup_dir = Path(os.getenv("KB_BACKUP_DIR", "./backups")).resolve()
keep_days = int(os.getenv("KB_KEEP_DAYS", "30"))
backup_dir.mkdir(parents=True, exist_ok=True)
ts = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
sql_path = backup_dir / f"kanboard_{db}_{ts}.sql"
gz_path = backup_dir / f"{sql_path.name}.gz"
# Bezpečně: vytvoříme dočasný mysql config soubor, aby heslo nebylo v "ps"
cnf_path = backup_dir / f".mysql_{db}_{ts}.cnf"
cnf_path.write_text(
"[client]\n"
f"host={host}\n"
f"port={port}\n"
f"user={user}\n"
f"password={password}\n",
encoding="utf-8"
)
try:
# omezit práva (na Linuxu/Unraid ok; na Windows to ignoruj)
try:
os.chmod(cnf_path, 0o600)
except Exception:
pass
# Mysqldump kompletní pro obnovu
dump_cmd = [
str(MYSQLDUMP),
f"--defaults-extra-file={str(cnf_path)}",
"--single-transaction",
"--routines",
"--triggers",
"--events",
"--hex-blob",
"--default-character-set=utf8mb4",
"--set-gtid-purged=OFF",
"--databases", db,
]
print(f"[OK] Dělám dump DB '{db}' -> {gz_path}")
# Dump do .sql a rovnou gzip
with subprocess.Popen(dump_cmd, stdout=subprocess.PIPE) as proc:
if proc.stdout is None:
raise SystemExit("Nepodařilo se získat stdout z mysqldump.")
with gzip.open(gz_path, "wb", compresslevel=6) as gz:
shutil.copyfileobj(proc.stdout, gz)
rc = proc.wait()
if rc != 0:
raise SystemExit(f"mysqldump selhal (exit={rc}).")
# Malá kontrola velikosti
size = gz_path.stat().st_size
if size < 200: # hodně hrubé
raise SystemExit(f"Dump je podezřele malý ({size} B) něco je špatně.")
# Retence
cutoff = datetime.now() - timedelta(days=keep_days)
for f in backup_dir.glob("kanboard_*_*.sql.gz"):
try:
if datetime.fromtimestamp(f.stat().st_mtime) < cutoff:
f.unlink(missing_ok=True)
except Exception:
pass
print(f"[OK] Hotovo. Velikost: {size/1024/1024:.2f} MB")
finally:
try:
cnf_path.unlink(missing_ok=True)
except Exception:
pass
if __name__ == "__main__":
main()
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.