"""Install receipt-driven cleanup; restart only private HTTP bridges, never workers.""" import datetime,hashlib,json,pathlib,shutil,sqlite3,subprocess,time,urllib.request,urllib.error root=pathlib.Path('/home/ps/huobao-video-cleanup') expected='646600a3c34354689b8d5aec0927b7481583da5478619e4e172f42583e5f4ffc' bridges=[{'name':'huobao-model-bridge','folder':'/home/ps/huobao-model-bridge','database':'/home/ps/huobao-model-bridge/state/jobs.sqlite3','normalizer':'canvas-h3-prompt-normalizer-healthy-20261026','port':18792}, {'name':'huobao-vdn-bridge','folder':'/home/ps/huobao-vdn/bridge','database':'/home/ps/huobao-vdn/bridge-state/jobs.sqlite3','normalizer':'huobao-vdn-normalizer','port':18794}] workers={'default':'comfyui','gpu1_8189':'comfyui-manju','gpu3':'h3-caption-gpu3-canary-8a5f','gpu1':'huobao-comfy-gpu1'} names=list(workers.values())+[b['normalizer'] for b in bridges] def identities(): return {i['Name']:{'id':i['Id'],'started':i['State']['StartedAt']} for i in json.loads(subprocess.check_output(['docker','inspect',*names],text=True))} before=identities() for filename in ['comfy_video_cleanup.candidate.py','video_cleanup_api.candidate.py','bridge-cleanup.candidate.py']: compile((root/filename).read_text(),filename,'exec') for entry in bridges: path=pathlib.Path(entry['folder'])/'bridge.py' assert hashlib.sha256(path.read_bytes()).hexdigest()==expected,'Bridge changed since review' assert not (path.parent/'video_cleanup_api.py').exists(),'Unexpected pre-existing cleanup module' unit=pathlib.Path.home()/'.config/systemd/user/huobao-video-cleanup.service' assert not unit.exists(),'Unexpected existing service; review first' backup=root/('backup-'+datetime.datetime.now().strftime('%Y%m%d-%H%M%S'));backup.mkdir(mode=0o700) for entry in bridges: folder=pathlib.Path(entry['folder']);shutil.copy2(folder/'bridge.py',backup/(entry['name']+'.py')) with sqlite3.connect('file:'+entry['database']+'?mode=ro',uri=True) as source,sqlite3.connect(backup/(entry['name']+'.sqlite3')) as target:source.backup(target) shutil.copy2(root/'comfy_video_cleanup.candidate.py',root/'comfy_video_cleanup.py') config={'bridges':[{k:b[k] for k in ['name','database','normalizer']}|{'workers':workers} for b in bridges]} (root/'config.json').write_text(json.dumps(config,indent=2));(root/'config.json').chmod(0o600) unit.parent.mkdir(parents=True,exist_ok=True) unit.write_text('[Unit]\nDescription=Huobao verified video cleanup\n\n[Service]\nType=simple\nWorkingDirectory=/home/ps/huobao-video-cleanup\nExecStart=/usr/bin/python3 /home/ps/huobao-video-cleanup/comfy_video_cleanup.py /home/ps/huobao-video-cleanup/config.json\nRestart=on-failure\nRestartSec=10\nTimeoutStopSec=250\nNoNewPrivileges=true\nUMask=0077\n\n[Install]\nWantedBy=default.target\n') def request(entry,path,body=None,auth=True): cfg=json.loads((pathlib.Path(entry['folder'])/'config.json').read_text()) headers={'Content-Type':'application/json'} if auth:headers['Authorization']='Bearer '+cfg['token'] req=urllib.request.Request(f"http://192.168.110.111:{entry['port']}"+path,data=None if body is None else json.dumps(body).encode(),headers=headers) try: with urllib.request.urlopen(req,timeout=15) as response:return response.status except urllib.error.HTTPError as error:return error.code changed=[] try: for entry in bridges: folder=pathlib.Path(entry['folder']);shutil.copy2(root/'video_cleanup_api.candidate.py',folder/'video_cleanup_api.py') shutil.copy2(root/'bridge-cleanup.candidate.py',folder/'bridge.py');changed.append(entry) subprocess.run(['docker','restart','--timeout','60',entry['name']],check=True,capture_output=True) for attempt in range(15): try: if request(entry,'/v1/models')==200:break except OSError:pass time.sleep(1) else:raise RuntimeError('Bridge health check failed') receipt={'version':1,'index':0,'sha256':'a'*64,'bytes':1} endpoint='/v2/video_generation/unknown-cleanup-selftest/cleanup' assert request(entry,endpoint,receipt)==404 assert request(entry,endpoint,receipt,auth=False)==401 with sqlite3.connect(entry['database']) as db:assert db.execute('select count(*) from video_cleanup_acks').fetchone()[0]==0 print(entry['name'],'receipt endpoint ready',flush=True) subprocess.run(['systemctl','--user','daemon-reload'],check=True,capture_output=True) subprocess.run(['systemctl','--user','enable','--now','huobao-video-cleanup.service'],check=True,capture_output=True) time.sleep(1) assert subprocess.check_output(['systemctl','--user','is-active','huobao-video-cleanup.service'],text=True).strip()=='active' assert identities()==before,'Unexpected model/normalizer restart' report={'installed':True,'backup':str(backup),'service':'huobao-video-cleanup.service','model_services_not_restarted':True,'existing_jobs_not_cancelled':True,'pending_cleanup_requests':0} (root/'deployment.json').write_text(json.dumps(report,indent=2));print(json.dumps(report)) except Exception: subprocess.run(['systemctl','--user','disable','--now','huobao-video-cleanup.service'],capture_output=True) for entry in changed: folder=pathlib.Path(entry['folder']);shutil.copy2(backup/(entry['name']+'.py'),folder/'bridge.py') (folder/'video_cleanup_api.py').unlink(missing_ok=True) subprocess.run(['docker','restart','--timeout','60',entry['name']],capture_output=True) raise