Add latest changes

Dieser Commit ist enthalten in:
2025-07-03 20:38:33 +00:00
Ursprung 63f3d92724
Commit 6f6cde65db
129 geänderte Dateien mit 3998 neuen und 1199 gelöschten Zeilen

Datei anzeigen

@@ -3,6 +3,8 @@ import time
import gzip
import logging
import subprocess
import json
import shutil
from pathlib import Path
from datetime import datetime
from zoneinfo import ZoneInfo
@@ -10,7 +12,7 @@ from cryptography.fernet import Fernet
from db import get_db_connection, get_db_cursor
from config import BACKUP_DIR, DATABASE_CONFIG, EMAIL_ENABLED, BACKUP_ENCRYPTION_KEY
from utils.audit import log_audit
from utils.github_backup import GitHubBackupManager, create_server_backup as create_server_backup_impl
from utils.github_backup import GitHubBackupManager, create_server_backup_impl
logger = logging.getLogger(__name__)
@@ -125,6 +127,10 @@ def create_backup(backup_type="manual", created_by=None):
send_backup_notification(True, filename, filesize, duration)
logger.info(f"Backup successfully created: {filename}")
# Apply retention policy - keep only last 5 local backups
cleanup_old_backups("database", 5)
return True, filename
except Exception as e:
@@ -224,6 +230,69 @@ def send_backup_notification(success, filename, filesize=None, duration=None, er
logger.info(f"Email notification prepared: Backup {'successful' if success else 'failed'}")
def cleanup_old_backups(backup_type="database", keep_count=5):
"""Clean up old local backups, keeping only the most recent ones"""
try:
# Get list of local backups from database
with get_db_connection() as conn:
with get_db_cursor(conn) as cur:
cur.execute("""
SELECT id, filename, filepath
FROM backup_history
WHERE backup_type = %s
AND status = 'success'
AND local_deleted = FALSE
AND filepath IS NOT NULL
ORDER BY created_at DESC
""", (backup_type,))
backups = cur.fetchall()
if len(backups) <= keep_count:
logger.info(f"No cleanup needed. Found {len(backups)} {backup_type} backups, keeping {keep_count}")
return
# Delete old backups
backups_to_delete = backups[keep_count:]
deleted_count = 0
for backup_id, filename, filepath in backups_to_delete:
try:
# Check if file exists
if filepath and os.path.exists(filepath):
os.unlink(filepath)
logger.info(f"Deleted old backup: {filename}")
# Update database
with get_db_connection() as conn:
with get_db_cursor(conn) as cur:
cur.execute("""
UPDATE backup_history
SET local_deleted = TRUE
WHERE id = %s
""", (backup_id,))
conn.commit()
deleted_count += 1
else:
# File doesn't exist, just update database
with get_db_connection() as conn:
with get_db_cursor(conn) as cur:
cur.execute("""
UPDATE backup_history
SET local_deleted = TRUE
WHERE id = %s
""", (backup_id,))
conn.commit()
except Exception as e:
logger.error(f"Failed to delete backup {filename}: {e}")
logger.info(f"Backup cleanup completed. Deleted {deleted_count} old {backup_type} backups")
except Exception as e:
logger.error(f"Backup cleanup failed: {e}")
def create_backup_with_github(backup_type="manual", created_by=None, push_to_github=True, delete_local=True):
"""Create backup and optionally push to GitHub"""
# Create the backup
@@ -242,7 +311,8 @@ def create_backup_with_github(backup_type="manual", created_by=None, push_to_git
db_backup_dir.mkdir(exist_ok=True)
target_path = db_backup_dir / filename
filepath.rename(target_path)
# Use shutil.move instead of rename to handle cross-device links
shutil.move(str(filepath), str(target_path))
# Push to GitHub
github = GitHubBackupManager()
@@ -269,8 +339,8 @@ def create_backup_with_github(backup_type="manual", created_by=None, push_to_git
conn.commit()
else:
logger.error(f"Failed to push to GitHub: {git_result}")
# Move file back
target_path.rename(filepath)
# Move file back using shutil
shutil.move(str(target_path), str(filepath))
except Exception as e:
logger.error(f"GitHub upload error: {str(e)}")
@@ -279,6 +349,63 @@ def create_backup_with_github(backup_type="manual", created_by=None, push_to_git
return True, filename
def create_container_server_backup_info(created_by="system"):
"""Create a server info backup in container environment"""
try:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"server_backup_info_{timestamp}.json"
filepath = Path("/app/backups") / filename
# Collect server info available in container
server_info = {
"backup_type": "server_info",
"created_at": datetime.now().isoformat(),
"created_by": created_by,
"container_environment": True,
"message": "Full server backups nur über Host-System möglich. Dies ist eine Info-Datei.",
"docker_compose": None,
"env_vars": {},
"existing_backups": []
}
# Try to read docker-compose if mounted
if os.path.exists("/app/docker-compose.yaml"):
try:
with open("/app/docker-compose.yaml", 'r') as f:
server_info["docker_compose"] = f.read()
except:
pass
# Try to read env vars (without secrets)
if os.path.exists("/app/.env"):
try:
with open("/app/.env", 'r') as f:
for line in f:
if '=' in line and not any(secret in line.upper() for secret in ['PASSWORD', 'SECRET', 'KEY']):
key, value = line.strip().split('=', 1)
server_info["env_vars"][key] = "***" if len(value) > 20 else value
except:
pass
# List existing server backups
if os.path.exists("/app/server-backups"):
try:
server_info["existing_backups"] = sorted(os.listdir("/app/server-backups"))[-10:]
except:
pass
# Write info file
with open(filepath, 'w') as f:
json.dump(server_info, f, indent=2)
logger.info(f"Container server backup info created: {filename}")
return True, str(filepath)
except Exception as e:
logger.error(f"Container server backup info failed: {e}")
return False, str(e)
def create_server_backup(created_by=None, push_to_github=True, delete_local=True):
"""Create full server backup"""
start_time = time.time()
@@ -296,7 +423,7 @@ def create_server_backup(created_by=None, push_to_github=True, delete_local=True
conn.commit()
try:
# Create server backup
# Create server backup - always use full backup now
success, result = create_server_backup_impl(created_by)
if not success:
@@ -353,6 +480,9 @@ def create_server_backup(created_by=None, push_to_github=True, delete_local=True
log_audit('BACKUP', 'server', backup_id,
additional_info=f"Server backup created: {filename} ({filesize} bytes)")
# Apply retention policy - keep only last 5 local server backups
cleanup_old_backups("server", 5)
return True, filename
except Exception as e: