feat(docker): uptime from StartedAt, a restart is an event, host totals count physical devices only (#5153)
- Agent: started_at comes from inspect's State.StartedAt (nanoseconds
trimmed; Docker's zero time is "never started"), not the list's Created,
so a restarted container's uptime counts from its restart.
- A rising restart_count between two snapshots emits a "restart" event
("restart #3", or "3 restarts, now #5"), said instead of a start; a
restart then a death gives both. A count that falls (recreated under the
same name) says nothing. The timeline draws it as ↻.
- Network and disk I/O count what the kernel calls physical: interfaces
not under /sys/devices/virtual/net (bridges, docker0, veth, vxlan, tun),
block devices with a device behind them (not dm, md, zram), so a byte is
not counted twice. Where /sys calls everything virtual (an agent in LXC)
the name-filtered set is kept rather than reporting no traffic.
- Agent tests updated for #5152's (status, detail, containers) and
(is_manager, topology) shapes; the no-Docker disk test now states the
case it was passing for by accident.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,8 @@ _derive_events is a pure function (no DB), and ingest.py imports its models
|
||||
lazily inside functions, so importing it here doesn't register ORM tables —
|
||||
safe for the no-DB unit lane.
|
||||
"""
|
||||
import pytest
|
||||
|
||||
from plugins.docker.ingest import _derive_events
|
||||
|
||||
|
||||
@@ -69,6 +71,27 @@ def test_no_event_when_unchanged():
|
||||
|
||||
# ── container-log row shaping (m79, pure) ─────────────────────────────────────
|
||||
|
||||
@pytest.mark.parametrize("old_status, old_n, new, events", [
|
||||
# Docker restarted it between samples: a restart, not silence (#5153).
|
||||
("running", 2, _c("web", "running", restart_count=3), [("web", "restart", "restart #3")]),
|
||||
# Caught restarting, now back up: a restart, said instead of a start.
|
||||
("restarting", 2, _c("web", "running", restart_count=3), [("web", "restart", "restart #3")]),
|
||||
("running", 2, _c("web", "running", restart_count=5), [("web", "restart", "3 restarts, now #5")]),
|
||||
# Restarted, then died for good: both happened.
|
||||
("running", 3, _c("web", "exited", restart_count=4, exit_code=1),
|
||||
[("web", "restart", "restart #4"), ("web", "die", "exit 1")]),
|
||||
# Started by hand (the count did not move): a start.
|
||||
("exited", 2, _c("web", "running", restart_count=2, image="nginx"), [("web", "start", "nginx")]),
|
||||
# Recreated under the same name, so the count reset: no restart.
|
||||
("running", 5, _c("web", "running", restart_count=0), []),
|
||||
("running", 2, _c("web", "running", restart_count=2), []),
|
||||
])
|
||||
def test_restart_events(old_status, old_n, new, events):
|
||||
old = {"web": {"status": old_status, "health": None, "oom_killed": False, "exit_code": None,
|
||||
"restart_count": old_n}}
|
||||
assert _derive_events(old, [new]) == events
|
||||
|
||||
|
||||
def test_log_rows_shapes_and_filters():
|
||||
from datetime import datetime, timezone
|
||||
from plugins.docker.ingest import _log_rows
|
||||
|
||||
Reference in New Issue
Block a user