From e2c61801dc2204e0663ad974616fb2d410c0f91a Mon Sep 17 00:00:00 2001 From: Codex Bot Date: Sat, 31 Oct 2026 04:03:07 +0800 Subject: [PATCH] Recover only old dangling image cache without tagged releases or volumes --- .../creative-browser-diagnostics.yml | 65 ++++--------------- 1 file changed, 12 insertions(+), 53 deletions(-) diff --git a/.gitea/workflows/creative-browser-diagnostics.yml b/.gitea/workflows/creative-browser-diagnostics.yml index 8106a07..359a13a 100644 --- a/.gitea/workflows/creative-browser-diagnostics.yml +++ b/.gitea/workflows/creative-browser-diagnostics.yml @@ -1,68 +1,27 @@ -name: creative verified failed-image disk recovery +name: runner old dangling image cache recovery on: push: branches: [codex/creative-browser-diagnosis] jobs: diagnose: runs-on: ces-control - timeout-minutes: 25 + timeout-minutes: 15 steps: - - name: Reclaim only terminal project builds while preserving releases and live containers + - name: Reclaim old untagged unused image cache without volumes or tagged releases run: | + set -euo pipefail + df -h / + echo 'Dangling image cache count (before age filtering)' + docker image ls -q --filter dangling=true | sort -u | wc -l python3 -u - <<'PY' - import json,subprocess,re,fcntl,pathlib,shutil,time,urllib.request - failed=['01c0f6ca73ce39388c9b84a38292542ef977ab9a', '02267a73b95389be3895e41fb46cca5206557c4e', '0360a5165b93fa13a81b8213508a073ac7dab351', '03b8e46731af3a0218b65254d61a01bc4940b68e', '04df551f6a63737f5a6186037bed1067318200e6', '054e9930433ab4e76ec86604a6be4423aaac18e6', '084926823256e4d9ae6f445764307a2029c8ac92', '0e47bae6065001955b99f614de3f1cc1dbcaa5a7', '134bc2c9cc6d28b58656bb9decbaa9124b81b813', '174a3ef2666f9e93af6c5992183cbd1fdc8ad1a7', '1925d15272e0de66fbaa4dc684f3d8c2914307ec', '254ac628bee0ccc36a7e08f01eebba9428e0dc86', '28b9fb146482810e74bd14f51568b46c664fef3e', '29e4ac849b835adbec6c3699476ecf1dacf0b4c3', '2bf572d353e0cefdafc0148d044835185c95004e', '2df69ec1c6f8543f42d63d9d0fdeb8009b484fb3', '306fb223afe56d54ce15a0674b0536c4937a3547', '36d15dc7bf026640388dd84f417bc2507ca18cfc', '39fad306c331431e2e9f7c5a4d75c8ab04835441', '4de92fd05957b1474bd57d4612b7233dbb0f19e2', '5427df8ff33acb1b4d2e47a7951a5ac376098cc7', '5c89d27528dd8bb175d52b72e26c022d1d474997', '68155fc0f79b1f8410752a8aa55fe1a5620df34e', '6a7d9244364e4d2ac35e4968da2626f394f82876', '6c11c8ac26eef6b160a79c24d197fdfe5e8edf45', '6e594f3fbf64767cf4928f5890300076b84ce3e2', '7372783062700e5cea70774cd47170da1dba18bb', '922c7bd0d0e9f69e102488fee69567eb79888e2f', '9256dd27e14f9b9298ccf56e8a21c9efa208a260', '94932418ca026adf5c1283097e1740cd22bb5065', '968e7ff353f887c1187f407ca8b7666d2b437635', 'a1984e615a08f5539350e4762e10f3caee14eb37', 'a3435c463f3d15484cd12fc18e2fd81ef00fd526', 'ad398db781019606337faef8c083185030673bfc', 'b131e1b11d7fb7920426cb81599f1ea1d0c10192', 'b157504ca6dc02d145522436a83bc30c5453edeb', 'bcdcd0906b194a2f4090a1da89fb8d229f820260', 'c85bc1c959ae910a1ca6e2df203a42c29c6e57a9', 'd779245e0999944d6799361f79e9387513751b10', 'db4b00bad003d0f5c5a91d80519f950e4c13d4a7', 'dbc575ced74038ef713711410e21c706b5c59674', 'dd367e40ac8fce8b430a0a2878042df5d3de029b', 'dd75e57b665a04cc9895351f65e6658b6b60f327', 'de30ee4ec8ea0686d98554bab117e071fa5db409', 'df831a15ba949e8ba972c6d5589a9ecd6d9ef3a0', 'e920f90c7c56dd3dc02d22be54d92e690374c00b', 'ea7bbebb3eb308a3536c12f554bc5f88e7d7be19', 'eac2dd4cde1153e071ce38cfe96ec1dc7669e094', 'ee697494056e3e362471ecb3bbb8d714c93b8b49', 'fac685a81c10a3aaa88baa7092ba755ae9dc0ddf'] - review=['creative-studio-review:0c8cf7c4cd0b8f7d904349184efc9da22b9dffb9', 'creative-studio-review:40a607696132818d6de0e6223723dce89d830fd6', 'creative-studio-review:429e78c7222207854b0db5a0eddf9cec69406054', 'creative-studio-review:4faef8b766a87017dfb5d838c6ed89eff132fad8', 'creative-studio-review:53a4103308ba69411a26382ce8a5028b7ee444e2', 'creative-studio-review:7f7fc28e5797751b44e9df0148431a81e614d650', 'creative-studio-review:94193d485bf2a6cf4667e2466063ba8098e63100', 'creative-studio-review:cad84f8a6730f7780cc8c4d851e1c6f9814cb355', 'creative-studio-review:cfc668690469acd32ef7b378458c682070d04479', 'creative-studio-review:d8c06d6cc66b2b60813940332a54fc4a1344827f', 'creative-studio-review:eed5d43e210ff38ee24f10778a8becc99cfb0f62', 'creative-studio-review:f4f0d67306a4daa3f28b16e06aee001ae95bf101', 'creative-wiki-review:0c8cf7c4cd0b8f7d904349184efc9da22b9dffb9', 'creative-wiki-review:40a607696132818d6de0e6223723dce89d830fd6', 'creative-wiki-review:429e78c7222207854b0db5a0eddf9cec69406054', 'creative-wiki-review:4faef8b766a87017dfb5d838c6ed89eff132fad8', 'creative-wiki-review:53a4103308ba69411a26382ce8a5028b7ee444e2', 'creative-wiki-review:71da1173356dd5df7e5b5bda4ee0773ec8e18ff2', 'creative-wiki-review:94193d485bf2a6cf4667e2466063ba8098e63100', 'creative-wiki-review:cad84f8a6730f7780cc8c4d851e1c6f9814cb355', 'creative-wiki-review:cdcd4c4b94d445829d624800193c66955ff09704', 'creative-wiki-review:cfc668690469acd32ef7b378458c682070d04479', 'creative-wiki-review:d2eaabe0da98d1461408a270e8a1ac6b1d8c2cd8', 'creative-wiki-review:d8c06d6cc66b2b60813940332a54fc4a1344827f', 'creative-wiki-tests:0c8cf7c4cd0b8f7d904349184efc9da22b9dffb9', 'creative-wiki-tests:3d48f5042da0ce418b89f066126adbae8d843bac', 'creative-wiki-tests:40a607696132818d6de0e6223723dce89d830fd6', 'creative-wiki-tests:429e78c7222207854b0db5a0eddf9cec69406054', 'creative-wiki-tests:4faef8b766a87017dfb5d838c6ed89eff132fad8', 'creative-wiki-tests:53a4103308ba69411a26382ce8a5028b7ee444e2', 'creative-wiki-tests:71da1173356dd5df7e5b5bda4ee0773ec8e18ff2', 'creative-wiki-tests:cad84f8a6730f7780cc8c4d851e1c6f9814cb355', 'creative-wiki-tests:cdcd4c4b94d445829d624800193c66955ff09704', 'creative-wiki-tests:cfc668690469acd32ef7b378458c682070d04479', 'creative-wiki-tests:d2eaabe0da98d1461408a270e8a1ac6b1d8c2cd8', 'creative-wiki-tests:d8c06d6cc66b2b60813940332a54fc4a1344827f', 'creative-wiki-tests:fcc0aba8100c0aa1d4874c8e9b8c2dd31570069b'] - protected=set(['00e1b703986676a714d959abbc4302b12df65a32', '4b24745eb9595361bfcfecf12d2165f1d7eb4c30', '5c1c2bede630d092487bea3aaef7e594925d7b2f', '8d487fa457ce9c51f62da84fcdb125b0cb145a9f', '939e0026463e063293b864c0d42e3cbc615e8e8d', '9a603cf87e9b726a566ae68f4f479030e0d02629', 'a33151da3c4008e238adfb339638e944ccc55de4', 'ad1f83d39879e47b286428e59678564fa3f35e4c', 'b550c151bd350c77c2bf3efda8dbf2d9f224dbd1', 'be23fe7030d07f58f0154bfd2e2e21424f0238b7', 'd12f9a8dc3a5e12fb064be26a44b95af296d573b', 'dba97853792011d536b9559d35852fbc2ca35293', 'dce2998396633f3c8b70bc3ed60c01e08e814d15', 'e57f7b751840ccd1bb2592a56937690f3b5e8405', 'e6a10ff8555c05e96709e9a8ea21da784a3259f9'])|{'084926823256e4d9ae6f445764307a2029c8ac92'} - sha_pattern=re.compile(r'^[0-9a-f]{40}$') - locks=[] - for name in ['.image-lifecycle.lock','.deploy.lock']: - handle=open('/opt/prompt/'+name,'a');fcntl.flock(handle,fcntl.LOCK_EX|fcntl.LOCK_NB);locks.append(handle) - ledger=pathlib.Path('/opt/prompt/successful-releases').read_text().splitlines() - assert all(sha_pattern.fullmatch(value) for value in ledger) - protected.update(ledger[:3]) - current=[line.split('=',1)[1] for line in pathlib.Path('/opt/prompt/current/release.env').read_text().splitlines() if line.startswith('RELEASE_SHA=')] - assert len(current)==1 and sha_pattern.fullmatch(current[0]);protected.update(current) - print('PROTECTED RELEASES '+json.dumps(sorted(protected)),flush=True) + import json,subprocess,shutil,time,urllib.request before=shutil.disk_usage('/').free - subprocess.run(['df','-h','/'],check=True) - removed=[];kept=[];missing=0 - - def output(args):return subprocess.check_output(args,text=True) - def referenced(): - ids=output(['docker','ps','-aq']).split() - return set(output(['docker','inspect','--format','{{.Image}}',*ids]).split()) if ids else set() - - tags=list(review) - for sha in failed: - assert sha_pattern.fullmatch(sha) - if sha not in protected: - tags.extend(name+':'+sha for name in ['waterfall-wiki','waterfall-wiki-tests','prompt-studio']) - for tag in tags: - name,_,sha=tag.rpartition(':') - assert sha_pattern.fullmatch(sha) and name in ['creative-studio-review','creative-wiki-tests','creative-wiki-review','waterfall-wiki','waterfall-wiki-tests','prompt-studio'] - if sha in protected: - kept.append(tag);continue - result=subprocess.run(['docker','image','inspect','--format','{{.Id}}',tag],text=True,capture_output=True) - if result.returncode: - if 'no such image' in result.stderr.lower():missing+=1;continue - raise RuntimeError('Unable to verify image '+tag+': '+result.stderr[:200]) - image=result.stdout.strip() - if image in referenced(): - kept.append(tag);continue - result=subprocess.run(['docker','image','rm',tag],text=True,capture_output=True) - print(result.stdout,flush=True) - if result.returncode:raise RuntimeError('Docker refused tag removal '+tag+': '+result.stderr[:300]) - removed.append(tag) - print('TAG RECOVERY '+json.dumps({'removed':len(removed),'kept':kept,'missing':missing}),flush=True) - subprocess.run(['df','-h','/'],check=True) - # Default dangling-only pruning: one exact project label plus an age bound. - # No --all, no volumes, no containers, and no filesystem deletion. - subprocess.run(['docker','image','prune','--force','--filter','label=io.entroia.project=waterfall-wiki','--filter','until=24h'],check=True) + # Default dangling-only mode. Do not add --all or use system/volume prune. + subprocess.run(['docker','image','prune','--force','--filter','until=24h'],check=True) time.sleep(5) after=shutil.disk_usage('/').free - print('DISK RECOVERY '+json.dumps({'beforeFreeBytes':before,'afterFreeBytes':after,'netRecoveredBytes':after-before,'removedTagCount':len(removed)}),flush=True) - subprocess.run(['df','-h','/'],check=True) + print('DANGLING RECOVERY '+json.dumps({'beforeFreeBytes':before,'afterFreeBytes':after,'netRecoveredBytes':after-before}),flush=True) with urllib.request.urlopen('http://8.211.154.134:18131/api/health',timeout=20) as response: print('PUBLIC HEALTH '+response.read().decode(),flush=True) PY + df -h /