431f804037
The widget-dedup test imported plugins.docker.routes, which re-imports plugins.docker.models after the app already loaded the docker plugin — "Table 'docker_containers' is already defined". Same plugin-loader gotcha the host_agent query helpers avoid. Extract dedup_by_container_id into plugins/docker/dedup.py (imports no ORM models, so it's safe to import in either environment); routes.py imports it from there and the test targets the model-free module. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016Jg27rgypiW2efULXJDtMC
28 lines
1.1 KiB
Python
28 lines
1.1 KiB
Python
"""Model-free Docker view helpers.
|
|
|
|
Kept separate from routes.py/models.py so tests can import it directly: importing
|
|
a module that re-imports plugins.docker.models AFTER the app has loaded the docker
|
|
plugin raises "Table 'docker_containers' is already defined". This module touches
|
|
no ORM models, so it's safe to import in either environment.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
|
|
def dedup_by_container_id(containers: list) -> list:
|
|
"""Collapse containers double-reported across hosts. Swarm-aware agents on
|
|
every manager list cluster-wide tasks, so the same container (identical
|
|
container_id) arrives once per manager and would otherwise be counted N times.
|
|
Keep the first occurrence per non-empty container_id — callers order
|
|
running-first, so a running report wins over a stale stopped one. Rows without
|
|
a container_id (older agents) can't be matched, so they're kept as-is."""
|
|
seen: set[str] = set()
|
|
out = []
|
|
for c in containers:
|
|
cid = (c.container_id or "").strip()
|
|
if cid:
|
|
if cid in seen:
|
|
continue
|
|
seen.add(cid)
|
|
out.append(c)
|
|
return out
|