Files
AzerothAI/deploy/classic/backup.py
T
2026-09-25 18:23:08 -07:00

22 lines
1.5 KiB
Python

#!/usr/bin/env python3
"""Bounded daily backup of Classic persistent accounts, characters and dashboard."""
import argparse,gzip,json,os,pathlib,shutil,sqlite3,subprocess,time
p=argparse.ArgumentParser();p.add_argument('--root',type=pathlib.Path,required=True);a=p.parse_args();root=a.root
base=root/'backups';base.mkdir(mode=0o700,exist_ok=True)
target=base/time.strftime('%Y%m%dT%H%M%SZ',time.gmtime());target.mkdir(mode=0o700)
c=json.loads((root/'database-credentials.json').read_text())
try:
with gzip.open(target/'classic-auth-characters.sql.gz','wb') as out:
p=subprocess.Popen(['docker','exec','-e','MYSQL_PWD','azerothai-classic-db','mysqldump','-uroot','--single-transaction','--set-gtid-purged=OFF','--databases','classicrealmd','classiccharacters'],stdout=subprocess.PIPE,stderr=subprocess.PIPE,env=dict(os.environ,MYSQL_PWD=c['root']))
shutil.copyfileobj(p.stdout,out)
if p.wait():raise RuntimeError('Classic backup failed')
dbs=[p for p in (root/'app-staging/.wrangler/state/v3/d1').rglob('*.sqlite') if p.name!='metadata.sqlite'];assert len(dbs)==1
source=sqlite3.connect(dbs[0]);dest=sqlite3.connect(target/'dashboard.sqlite');source.backup(dest);dest.close();source.close()
shutil.copytree(root/'run/etc',target/'config')
(target/'complete.json').write_text(json.dumps({'at':time.time(),'backend':'cmangos-classic'}))
for old in sorted(base.iterdir(),reverse=True)[3:]:
if old.is_dir() and (old/'complete.json').exists():shutil.rmtree(old)
print('Classic backup complete: '+str(target))
except Exception:
(target/'failed').touch();raise