fix: reconcile approved live VPS source and operations

This commit is contained in:
2026-10-13 18:04:15 +03:00
parent 36f508df75
commit 6385d60dff
57 changed files with 2474 additions and 4630 deletions
+3
View File
@@ -0,0 +1,3 @@
SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
15 2 * * * root /usr/bin/python3 /root/anwarpy-daily-backup.py >> /root/anwarpy-backups/daily.log 2>&1
+26
View File
@@ -0,0 +1,26 @@
#!/usr/bin/python3
"""Bounded daily backup. Never modifies application data or schema."""
from pathlib import Path
import subprocess, json, datetime, shutil, os
os.umask(0o077)
root=Path('/root/anwarpy-backups');root.mkdir(mode=0o700,exist_ok=True)
now=datetime.datetime.now(datetime.timezone.utc);folder=root/('daily-'+now.strftime('%Y%m%dT%H%M%SZ'));folder.mkdir(mode=0o700)
try:
with (folder/'database.dump').open('wb') as out:
subprocess.run(['docker','exec','anwarpi-db-1','pg_dump','-U','anwarpi','-d','anwarpi','-Fc'],stdout=out,check=True)
subprocess.run(['tar','-czf',str(folder/'source-config.tar.gz'),'-C','/root','anwarpi'],check=True)
info=json.loads(subprocess.check_output(['docker','inspect','anwarpi-web-1'],text=True))[0]
for mount in info['Mounts']:
if mount['Destination'] in ['/app/media','/app/files-private']:
subprocess.run(['tar','-czf',str(folder/(mount['Destination'].split('/')[-1]+'.tar.gz')),'-C',mount['Source'],'.'],check=True)
subprocess.run(['docker','cp',str(folder/'database.dump'),'anwarpi-db-1:/var/lib/postgresql/daily-archive-check.dump'],check=True)
archive=subprocess.check_output(['docker','exec','anwarpi-db-1','pg_restore','--list','/var/lib/postgresql/daily-archive-check.dump'],text=True)
assert 'TABLE DATA' in archive
record={'status':'ok','finished_at':now.isoformat(),'backup':str(folder),'image':info['Image'],'archive_list_valid':True}
(folder/'verification.json').write_text(json.dumps(record))
for old in root.glob('daily-*'):
if old.is_dir() and old!=folder and now.timestamp()-old.stat().st_mtime>30*86400:shutil.rmtree(old)
except Exception as error:
record={'status':'failed','finished_at':now.isoformat(),'error_type':type(error).__name__}
(root/'health.json').write_text(json.dumps(record));print(json.dumps(record));raise
(root/'health.json').write_text(json.dumps(record));print(json.dumps(record))