* Add one-shot mode and docker-given totals to stats API
- Add one-shot query option to container stats to skip the calculated
CPU percentage window, returning docker-given totals directly.
- Refactor container_stats() with translatable, structured Docker
errors and timeout handling instead of generic Docker exceptions.
- Translate low-level Docker errors into component-flavored errors
(NotRunningError/StatsTimeoutError/UnknownError) for Home Assistant,
Supervisor, and each plugin (Audio, Cli, CoreDNS, Multicast,
Observer) as well as apps, mirroring the existing App.stats()
pattern for consistent, informative API responses.
- Add a shared api_return_stats() helper to remove duplicated stats
handling logic across the 8 stats API endpoints.
- DockerContainerNotFoundError now inherits from DockerNotFound.
* Contain aiodocker _query access and split v1/v2 stats response model
- Contain the reach into aiodocker's protected _query internals (needed
for one-shot stats until aio-libs/aiodocker#1054 lands) to a single
DockerAPI._query_one_shot_stats() helper.
- Split the stats API response model between v1 (legacy, windowed CPU
percentage still available via opt-in one_shot query string) and v2
(always one-shot, no query string, cpu_percent dropped since it would
never carry a meaningful value). Both share the same
api_return_stats(stats, legacy=...) helper so the response model
stays in one place.
- DockerAPI.container_stats() keeps its existing one_shot keyword only;
the legacy/v1 vs v2 distinction is handled entirely in the API layer.
* Detect stopped/restarting containers in one-shot stats response
Docker returns a stub response containing only the container's id/name
(no cpu_stats/memory_stats/networks data) for a stopped or restarting
container instead of an error, even in one-shot mode - the not-running
check in daemon.ContainerStats happens before the one-shot branch, so
requesting one-shot stats doesn't change this. Detect the missing
online_cpus field (only ever present while running) and raise
DockerContainerNotRunningError instead of returning a payload that
DockerStats would otherwise turn into a successful all-zero response.
* Add tests for stats error paths introduced in one-shot/totals PR
- Cover DockerAPI.container_stats/_query_one_shot_stats edge cases: empty
one-shot response, empty windowed response, and the raw _query_one_shot_stats
helper.
- Add stats() error-translation tests (not-running, timeout, unknown) for the
audio, cli, multicast and observer plugins, none of which had any coverage.
- Add stats endpoint tests (v1 + v2) for the cli, audio, dns, multicast and
observer REST APIs, plus a v1 success-path test for the apps stats endpoint.
These close the codecov-flagged gaps for newly introduced code in this PR.
* Unify one-shot and windowed container_stats() code paths
Both modes now share the same error handling and not-running detection:
- The windowed path no longer inspects the container first to check its
running state. Docker returns the same id/name-only stub response (no
online_cpus in cpu_stats) for a stopped or restarting container in
windowed mode as it does in one-shot mode, so the existing online_cpus
presence check now covers both, closing a race window where a container
stopping between the inspect and the stats call would previously reach
the DockerStats parser with an incomplete payload.
- The windowed path builds its container handle via containers.container(),
which constructs a DockerContainer from the name with no I/O, instead of
containers.get(), which performs an unnecessary inspect call just to
fetch the same information the stats call already returns.
* Fix protected access pylint issue