"""Image listing — shared by the central images router and the agent.""" from __future__ import annotations from docker_client import DockerError, get_client, safe_call from services import update_service COMPOSE_PROJECT_LABEL = "com.docker.compose.project" def list_images() -> list[dict]: """Return one row per image tag, annotated with using-stacks + update status.""" try: client = get_client() images = safe_call(client.images.list) containers = safe_call(client.containers.list, all=True) except DockerError: return [] # Map image ref -> stacks using it. usage: dict[str, set[str]] = {} for c in containers: ref = c.attrs.get("Config", {}).get("Image") stack = c.labels.get(COMPOSE_PROJECT_LABEL) if ref: usage.setdefault(ref, set()) if stack: usage[ref].add(stack) cache = update_service.get_cache() result = [] for img in images: tags = img.tags or [] if not tags: continue for tag in tags: result.append( { "id": img.short_id, "tag": tag, "size": img.attrs.get("Size", 0), "created": img.attrs.get("Created"), "stacks": sorted(usage.get(tag, set())), "update": cache.get(tag), } ) result.sort(key=lambda r: r["tag"]) return result