Sync from main server - 2026-05-16 00:38:48

This commit is contained in:
root
2026-05-16 00:38:48 +02:00
parent 6158b34613
commit 53f36d0ac7
4 changed files with 239 additions and 136 deletions

View File

@@ -74,7 +74,7 @@ def get_vm_backups():
f"-o StrictHostKeyChecking=no -o ConnectTimeout=10 "
f"-o BatchMode=yes "
f"{VM_USER}@{VM_HOST} "
f"'ls -t /backups/main-server/myapps-backup-*.tar.gz 2>/dev/null | head -20'"
f"'ls -t /backups/cloudproject/myapps-backup-*.tar.gz 2>/dev/null | head -20'"
)
stdout, _ = _run(cmd, timeout=25)
if stdout:
@@ -85,7 +85,7 @@ def get_vm_backups():
except Exception as e:
print(f"[backups] VM backup fetch error: {e}")
else:
backup_dir = '/backups/main-server'
backup_dir = '/backups/cloudproject'
if os.path.exists(backup_dir):
files = glob.glob(f'{backup_dir}/myapps-backup-*.tar.gz')
files.sort(key=os.path.getmtime, reverse=True)
@@ -109,7 +109,7 @@ def audit_backup(backup_file, source='local'):
if source == 'local':
archive_path = f"/root/backups/{backup_file}"
else:
archive_path = f"/backups/main-server/{backup_file}"
archive_path = f"/backups/cloudproject/{backup_file}"
if not RUNNING_ON_MAIN_SERVER and source == 'local':
tmp_path = f"/tmp/audit_{backup_file}"
@@ -381,7 +381,7 @@ def delete_backup(backup_file, source='local'):
return True, f'Deleted {backup_file} from main server'
elif source == 'vm':
archive_path = f"/backups/main-server/{backup_file}"
archive_path = f"/backups/cloudproject/{backup_file}"
if not RUNNING_ON_MAIN_SERVER:
if not os.path.exists(archive_path):
return False, f'File not found: {archive_path}'
@@ -395,8 +395,8 @@ def delete_backup(backup_file, source='local'):
f"-o StrictHostKeyChecking=no -o ConnectTimeout=10 "
f"-o BatchMode=yes "
f"{VM_USER}@{VM_HOST} "
f"'rm -f /backups/main-server/{backup_file} "
f"/backups/main-server/{backup_file}.sha256'"
f"'rm -f /backups/cloudproject/{backup_file} "
f"/backups/cloudproject/{backup_file}.sha256'"
)
out, err = _run(cmd, timeout=30)
if err and 'No such file' not in err:

View File

@@ -81,7 +81,6 @@ def r2_test_connection() -> dict:
except Exception as e:
return {"success": False, "message": str(e), "bucket_exists": False}
def r2_ensure_bucket() -> tuple[bool, str]:
cfg = _get_r2_config()
bucket = cfg["bucket_name"]
@@ -125,6 +124,35 @@ def r2_list_backups() -> list[dict]:
except Exception:
return []
def r2_enforce_retention(max_backups: int = 5) -> list[str]:
"""Keep only the latest max_backups in R2, delete the rest. Returns list of deleted keys."""
if not r2_is_configured():
return []
cfg = _get_r2_config()
bucket = cfg["bucket_name"]
deleted = []
try:
client = _get_r2_client()
resp = client.list_objects_v2(Bucket=bucket, Prefix="backups/")
# Only count real archives, not .sha256 files
objects = sorted(
[o for o in resp.get("Contents", []) if not o["Key"].endswith(".sha256")],
key=lambda x: x["LastModified"],
reverse=True # newest first
)
to_delete = objects[max_backups:] # everything beyond the 5 latest
for obj in to_delete:
key = obj["Key"]
client.delete_object(Bucket=bucket, Key=key)
# Also delete the sha256 companion if it exists
try:
client.delete_object(Bucket=bucket, Key=key + ".sha256")
except Exception:
pass
deleted.append(key)
except Exception as e:
print(f"R2 retention error: {e}")
return deleted
def r2_delete_backup(key: str) -> tuple[bool, str]:
cfg = _get_r2_config()
@@ -227,6 +255,10 @@ def r2_upload_async(local_path: str, job_id: str) -> None:
_upload_jobs[job_id]["log"].append(
f"Upload complete in {elapsed}s — r2://{bucket}/{object_key}"
)
# Enforce R2 retention — keep only 5 latest
deleted = r2_enforce_retention(max_backups=5)
for dk in deleted:
_upload_jobs[job_id]["log"].append(f"🗑️ Pruned old R2 backup: {dk.replace('backups/', '')}")
_upload_jobs[job_id]["status"] = "done"
_upload_jobs[job_id]["progress"] = 100
_upload_jobs[job_id]["object_key"] = object_key