server-up/tools/controleer_images.py
Ramon 42bd87047a
All checks were successful
Deploy server-up (dev) / deploy (push) Successful in 12m38s
v0.8.20-beta - Prometheus startte niet, en 23 apps erbij
- apps/prometheus was kapot: het koppelde een lege map op /etc/prometheus en
  startte met --config.file naar een bestand dat er nooit kwam. Er zit nu een
  startconfiguratie bij, met koppelvelden naar node-exporter en cAdvisor
- De meeste apps van deze ronde zijn de ontbrekende helft van wat er al stond:
  node-exporter, cAdvisor en Alertmanager maken Prometheus bruikbaar; Loki en
  Alloy bewaren logs waar Dozzle alleen live meekijkt; Unbound zoekt DNS zelf op
  in plaats van door te vragen aan Google of Cloudflare
- Domeinen die ontbraken: evcc (energie), Healthchecks (cronbewaking),
  Infisical (geheimen voor applicaties), Music Assistant, pgAdmin
- Verder Crafty, Manyfold, ErsatzTV, FitTrackee, ComfyUI, Omada, en de zwaardere
  Zabbix, Graylog, Wazuh, NetBox, Seafile en OpenCloud. Van 218 naar 241 apps
- Nieuw tools/controleer_images.py: controleert of elk image echt bestaat. De
  ad-hoc versie draaide met zestien verzoeken tegelijk en meldde negen
  ontbrekende images die alle negen wel bestonden -- registries knijpen af, en
  dat is niet te onderscheiden van een ontbrekend image. Nu vier tegelijk met
  opnieuw proberen, en als stap in de drie workflows

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q9eqpADJSRs49SoGGr4NAy
2026-08-01 04:06:26 +02:00

77 lines
2.6 KiB
Python

"""Controleer of elk image in de catalogus echt bestaat bij zijn registry.
Aanleiding: `ghcr.io/plexguide/huntarr` stond in de ARR-stack terwijl dat project
offline was gehaald en het image niet meer bestond. Daarna bleken ook Forgejo,
Planka en Baby Buddy naar tags te wijzen die er niet zijn. Zulke fouten merk je
anders pas als iemand op installeren drukt.
python3 tools/controleer_images.py [--json]
**Waarom dit langzaam gaat.** Registries knijpen af bij te veel verzoeken achter
elkaar, en een afgeknepen verzoek ziet er precies zo uit als een image dat niet
bestaat. Eén ronde met zestien tegelijk leverde negen valse meldingen op — waarop
je bijna een werkend sjabloon gaat "repareren". Daarom weinig tegelijk, en wat
niet meteen lukt gaat opnieuw met oplopende pauzes.
"""
from __future__ import annotations
import concurrent.futures as cf
import json
import re
import sys
import time
from pathlib import Path
WORTEL = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(WORTEL / "server-up" / "core"))
import registry # noqa: E402
TEGELIJK = 4
POGINGEN = 3
IMAGE_RE = re.compile(r"^\s*image:\s*(\S+)\s*$", re.M)
def images() -> dict[str, list[str]]:
"""Elk image in de catalogus, met de apps die het gebruiken."""
uit: dict[str, list[str]] = {}
for pad in sorted((WORTEL / "apps").glob("*/files/*.yaml")):
for m in IMAGE_RE.finditer(pad.read_text(encoding="utf-8")):
naam = m.group(1)
if "<<" in naam: # nog niet gerenderd
continue
uit.setdefault(naam, []).append(pad.parent.parent.name)
return uit
def bestaat(image: str) -> bool:
for poging in range(POGINGEN):
try:
if registry.manifest_digest(image):
return True
except Exception:
pass
if poging < POGINGEN - 1:
time.sleep(2 ** poging) # 1s, 2s
return False
def main() -> int:
alles = images()
with cf.ThreadPoolExecutor(TEGELIJK) as ex:
uitslag = dict(zip(alles, ex.map(bestaat, alles)))
fout = {i: alles[i] for i, ok in uitslag.items() if not ok}
if "--json" in sys.argv:
print(json.dumps({"gecontroleerd": len(alles), "fout": fout}, indent=2))
else:
print(f"{len(alles)} unieke images gecontroleerd")
for image, apps in sorted(fout.items()):
print(f"{image} ({', '.join(sorted(set(apps)))})")
if not fout:
print(" alle images bestaan")
return 1 if fout else 0
if __name__ == "__main__":
raise SystemExit(main())