#!/usr/bin/env python3 """Prove an operator backup restores in an isolated loopback JVM; no production mutation.""" import argparse import io, json, os, runpy, shutil, socket, subprocess, tempfile, time, urllib.request, zipfile from pathlib import Path root=Path(__file__).resolve().parents[1] parser=argparse.ArgumentParser(description=__doc__) parser.add_argument('--backup', type=Path, required=True) parser.add_argument('--java', type=Path, default=Path(os.environ.get('JAVA_HOME', '/usr'))/'bin/java') args=parser.parse_args() scope=runpy.run_path(str(root/'scripts/deploy-update-remote.py')) scope.update(runpy.run_path(str(root/'scripts/backup.py'))) restore=runpy.run_path(str(root/'scripts/restore-remote.py'), init_globals=scope) archive=args.backup.resolve(strict=True) metadata=scope['verify'](archive) java=args.java.resolve(strict=True) (root/'work').mkdir(exist_ok=True) with tempfile.TemporaryDirectory(prefix='restore-proof-', dir=root/'work') as temporary: home=Path(temporary) class Local(scope['Deployment']): def __init__(self): super().__init__(home) self.process=None self.site.mkdir(parents=True) with socket.socket() as sock: sock.bind(('127.0.0.1',0));self.port=sock.getsockname()[1] def preflight(self, check_data=True, allow_restore=False): if not allow_restore and (self.app/'pending-restore.json').exists(): raise RuntimeError('pending restore') def command(self,*args): if '--property=ActiveState' in args:return 'active' if self.process and self.process.poll() is None else 'inactive' return '0' def maintenance(self):self.flag.write_text('isolated maintenance') def start(self): if self.process and self.process.poll() is None:return with (home/'application.log').open('ab') as log: self.process=subprocess.Popen([str(java),'-Xmx256m','-XX:MaxMetaspaceSize=192m','-XX:ActiveProcessorCount=2','-jar',str(self.app/'current/werkjournal.jar'),f'--server.port={self.port}','--server.address=127.0.0.1','--werkjournal.guest-mode=true','--werkjournal.push.enabled=false','--werkjournal.mail.sendmail=/bin/false'],cwd=self.app,env={'HOME':str(home),'PATH':'/usr/bin:/bin','LANG':'C.UTF-8'},stdout=log,stderr=subprocess.STDOUT) def stop(self): if self.process and self.process.poll() is None: self.process.terminate() try:self.process.wait(timeout=30) except subprocess.TimeoutExpired:self.process.kill();self.process.wait();raise def ready(self,expected): deadline=time.monotonic()+90 while time.monotonic()