Commit Graph
1 Commits
Author SHA1 Message Date
Mike Degatano 2d153ac497 Add one-shot mode and docker-given totals to stats API (#7168)
* 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
2026-08-31 17:11:38 +02:00