Files
IKAR/tool/cleanup_old_ikar.py

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))