notebookvb

This commit is contained in:
Vladimir Buzalka
2026-04-29 06:51:47 +02:00
parent a1b9c93506
commit a9c143ba24
141 changed files with 30711 additions and 0 deletions
@@ -0,0 +1,149 @@
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Nightly Medicus automatic restore
---------------------------------
Workflow:
1️⃣ Kill all Medicus processes
2️⃣ Restart Firebird service (to release all open connections)
3️⃣ Clean restore folder
4️⃣ Find and extract newest Medicus backup (.fbk or .zip)
5️⃣ Restore database using gbak (Firebird service kept running)
6️⃣ Restart Firebird again to refresh state
7️⃣ Log all actions with timestamps
"""
import os
import psutil
import shutil
import zipfile
import subprocess
from pathlib import Path
from datetime import datetime
import time
# =========================================
# 🔧 CONFIGURATION
# =========================================
FIREBIRD_GBAK = Path(r"C:\Program Files\Firebird\Firebird_2_5_CGM\bin\gbak.exe")
BACKUP_DIR = Path(r"G:\OnedriveOrdinace\OneDrive\MedicusBackup")
RESTORE_DIR = Path(r"Z:\Medicus 3\restore")
TARGET_DB = Path(r"Z:\Medicus 3\data\MEDICUS.FDB")
SERVICE_NAME = "FirebirdServerCGM"
USER = "SYSDBA"
PASSWORD = "masterkey"
LOG_FILE = RESTORE_DIR / f"nightly_restore_{datetime.now():%Y%m%d_%H%M%S}.log"
# =========================================
# 🪓 1) Kill Medicus processes
# =========================================
def kill_medicus():
targets = ["Medicus.exe", "MedicusServer.exe", "MedicusUpdater.exe"]
with open(LOG_FILE, "w", encoding="utf-8") as log:
log.write(f"==== NIGHTLY RESTORE START {datetime.now():%Y-%m-%d %H:%M:%S} ====\n")
for proc in psutil.process_iter(["name", "pid"]):
try:
if proc.info["name"] and proc.info["name"].lower() in [t.lower() for t in targets]:
log.write(f"Killing {proc.info['name']} (PID {proc.pid})\n")
proc.kill()
except (psutil.NoSuchProcess, psutil.AccessDenied):
continue
log.write("All Medicus processes terminated.\n")
# =========================================
# ⚙️ 2) Firebird service control
# =========================================
def service_cmd(action):
cmd = f'net {action} "{SERVICE_NAME}"'
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
return result.returncode == 0, result.stdout + result.stderr
def restart_firebird(label):
ok, out = service_cmd("stop")
with open(LOG_FILE, "a", encoding="utf-8") as log:
log.write(f"\n--- Restart Firebird ({label}) ---\n")
log.write(f"Stopping {SERVICE_NAME}...\n{out}\n")
time.sleep(5)
ok, out = service_cmd("start")
with open(LOG_FILE, "a", encoding="utf-8") as log:
log.write(f"Starting {SERVICE_NAME}...\n{out}\n")
# =========================================
# 🧹 3) Clean restore folder
# =========================================
def clean_restore_folder():
for item in RESTORE_DIR.glob("*"):
try:
if item.is_file():
item.unlink()
elif item.is_dir():
shutil.rmtree(item)
except Exception as e:
with open(LOG_FILE, "a", encoding="utf-8") as log:
log.write(f"⚠️ Could not delete {item}: {e}\n")
# =========================================
# 💾 4) Find newest backup and prepare .fbk
# =========================================
def prepare_backup():
backups = list(BACKUP_DIR.glob("Medicus_*.fbk")) + list(BACKUP_DIR.glob("Medicus_*.zip"))
if not backups:
raise SystemExit(f"❌ No Medicus backups found in {BACKUP_DIR}")
latest = max(backups, key=lambda f: f.stat().st_mtime)
fbk_path = RESTORE_DIR / (latest.stem + ".fbk")
with open(LOG_FILE, "a", encoding="utf-8") as log:
log.write(f"\nUsing backup: {latest}\n")
if latest.suffix.lower() == ".fbk":
shutil.copy2(latest, fbk_path)
else:
with zipfile.ZipFile(latest, "r") as zf:
fbk_files = [n for n in zf.namelist() if n.lower().endswith(".fbk")]
if not fbk_files:
raise SystemExit("❌ ZIP file does not contain .fbk!")
zf.extract(fbk_files[0], RESTORE_DIR)
extracted = RESTORE_DIR / fbk_files[0]
if extracted != fbk_path:
shutil.move(extracted, fbk_path)
return fbk_path
# =========================================
# 🧩 5) Restore database using gbak
# =========================================
def restore_database(fbk_path):
cmd = f'"{FIREBIRD_GBAK}" -rep "{fbk_path}" "{TARGET_DB}" -user {USER} -pas {PASSWORD}'
with open(LOG_FILE, "a", encoding="utf-8") as log:
log.write(f"\nRunning restore command:\n{cmd}\n")
result = subprocess.run(cmd, shell=True, text=True, capture_output=True)
with open(LOG_FILE, "a", encoding="utf-8") as log:
log.write(result.stdout)
log.write(result.stderr)
log.write(f"Return code: {result.returncode}\n")
if result.returncode == 0:
print("✅ Medicus database successfully restored!")
else:
print("❌ Restore failed! Check log for details.")
# =========================================
# 🚀 MAIN WORKFLOW
# =========================================
if __name__ == "__main__":
kill_medicus()
restart_firebird("before restore")
clean_restore_folder()
fbk = prepare_backup()
restore_database(fbk)
restart_firebird("after restore")
with open(LOG_FILE, "a", encoding="utf-8") as log:
log.write(f"\n==== RESTORE COMPLETED {datetime.now():%Y-%m-%d %H:%M:%S} ====\n")
print(f"📝 Full log saved to {LOG_FILE}")