#!/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