58 lines
3.5 KiB
Python
58 lines
3.5 KiB
Python
"""Remove only the retired IKAR installation after a verified replacement."""
|
|
from pathlib import Path
|
|
import datetime, json, os, shutil, sqlite3, subprocess, tarfile, tempfile, urllib.request
|
|
|
|
root=Path('/mnt/data/ikar_server')
|
|
rollback=root/'rollback'
|
|
assert os.geteuid()==0 and os.path.ismount('/mnt/data')
|
|
health=json.load(urllib.request.urlopen('http://127.0.0.1:5099/health',timeout=15))
|
|
assert health['status']=='ok' and health['database']=='ok' and health['disk']=='ok'
|
|
baseline=[json.loads(x) for x in (rollback/'services-before.jsonl').read_text().splitlines() if x.strip()]
|
|
current={x['Names']:x for x in map(json.loads,subprocess.check_output(['docker','ps','--format','{{json .}}'],text=True).splitlines())}
|
|
for before in baseline:
|
|
assert current[before['Names']]['ID']==before['ID'] and current[before['Names']]['State']=='running'
|
|
|
|
archive=rollback/'old-ikar-20261005.tar.gz'
|
|
with tarfile.open(archive) as t, tempfile.TemporaryDirectory(dir=rollback,prefix='verify-') as temp:
|
|
member=next(x for x in t.getmembers() if x.isfile() and x.name.endswith('/ikar.db'))
|
|
database=Path(temp)/'old.db'
|
|
with t.extractfile(member) as source, database.open('wb') as target: shutil.copyfileobj(source,target)
|
|
with sqlite3.connect(f'file:{database}?mode=ro',uri=True) as db: assert db.execute('pragma quick_check').fetchone()[0]=='ok'
|
|
|
|
containers=['ikar-server','ikar-turn']
|
|
existing=set(subprocess.check_output(['docker','ps','-a','--format','{{.Names}}'],text=True).splitlines())
|
|
for name in containers:
|
|
if name in existing:
|
|
state=json.loads(subprocess.check_output(['docker','inspect','--format','{{json .State}}',name],text=True))
|
|
assert not state['Running']
|
|
subprocess.run(['docker','rm',name],check=True,stdout=subprocess.DEVNULL)
|
|
|
|
# Preserve the previous backup history within the new rollback directory.
|
|
old_backups=Path('/mnt/data/ikar-backups')
|
|
if old_backups.exists():
|
|
assert old_backups.resolve()==old_backups and not (rollback/'legacy-backups').exists()
|
|
shutil.move(str(old_backups),str(rollback/'legacy-backups'))
|
|
|
|
old_cron=subprocess.check_output(['crontab','-u','sevenhill','-l'],text=True)
|
|
(rollback/'old-sevenhill.crontab').write_text(old_cron)
|
|
os.chmod(rollback/'old-sevenhill.crontab',0o600)
|
|
lines=old_cron.splitlines()
|
|
new_lines=[line for line in lines if '/home/sevenhill/ikar-deploy/scripts/backup-ikar-data.sh' not in line]
|
|
if new_lines!=lines: subprocess.run(['crontab','-u','sevenhill','-'],input='\n'.join(new_lines)+'\n',text=True,check=True)
|
|
|
|
targets=[Path('/mnt/data/ikar-deploy'),Path('/mnt/data/ikar-data'),Path('/mnt/data/ikar-builds')]
|
|
for target in targets:
|
|
assert target.parent==Path('/mnt/data') and target.name in {'ikar-deploy','ikar-data','ikar-builds'} and target.resolve()==target
|
|
if target.exists():
|
|
if target.name=='ikar-builds':
|
|
with tarfile.open(rollback/'old-builds.tar.gz','w:gz') as t: t.add(target,arcname='ikar-builds')
|
|
os.chmod(rollback/'old-builds.tar.gz',0o600)
|
|
shutil.rmtree(target)
|
|
link=Path('/home/sevenhill/ikar-deploy')
|
|
if link.is_symlink():
|
|
assert os.readlink(link) in ('/mnt/data/ikar-deploy','../../mnt/data/ikar-deploy')
|
|
link.unlink()
|
|
report={'oldContainersRemoved':containers,'oldDirectoriesRemoved':[str(x) for x in targets], 'rollback':str(archive),'backupIntegrity':'ok','previousBackups':str(rollback/'legacy-backups'),'timestamp':datetime.datetime.now(datetime.timezone.utc).isoformat()}
|
|
(rollback/'cleanup.json').write_text(json.dumps(report,indent=2))
|
|
print(json.dumps(report))
|