feat(docker): Busiest Containers shows bars of the last hours beside each figure, scaled to the row's peak with a floor (#5214)
CI / lint (push) Successful in 4s
CI / integration (push) Failing after 59s
CI / unit (push) Failing after 1m27s
CI / publish (push) Skipped

The fill bars were a share of the host's capacity, a sliver on hosts with
80 cores. Each figure now sits beside 24 bars of the last 6 hours (1h/24h
per widget), each row scaled to its own peak but never below 1 core or
1 GiB (configurable per widget), so a 0.05-core container reads flat and
a bar's height means real load. One grouped date_bin query feeds them.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-07 15:05:06 -04:00
co-authored by Claude Opus 5.5
parent 97c864bf42
commit 05eaca3f2f
7 changed files with 242 additions and 36 deletions
@@ -0,0 +1,49 @@
"""Integration: Busiest Containers bars average each container's samples per
time bucket in one query (#5214). Two samples share a bucket and must merge
(lesson #5262). Requires STEWARD_DATABASE_URL."""
from __future__ import annotations
import asyncio
import os
import uuid
from datetime import datetime, timedelta, timezone
import pytest
pytestmark = pytest.mark.integration
@pytest.fixture
def app():
if not os.environ.get("STEWARD_DATABASE_URL"):
pytest.skip("needs Postgres")
from steward.app import create_app
return create_app(testing=False)
def test_recent_usage_averages_each_containers_bucket(app):
from plugins.docker.models import DockerMetric
from plugins.docker.service import bar_slots, recent_usage
from steward.models.hosts import Host
tag = uuid.uuid4().hex[:8]
hid = str(uuid.uuid4())
slots, width = bar_slots(datetime.now(timezone.utc), 6)
at = slots[-2] # a whole bucket, in the past
def m(name, secs, cpu, mem):
return DockerMetric(host_id=hid, container_name=name, scraped_at=at + timedelta(seconds=secs),
cpu_pct=cpu, mem_pct=0.0, mem_usage_bytes=mem)
async def go():
async with app.db_sessionmaker() as s:
async with s.begin():
s.add(Host(id=hid, name=f"dock-{tag}", address="10.9.9.4"))
async with s.begin():
s.add_all([m(f"a-{tag}", 10, 100.0, 1000), m(f"a-{tag}", 70, 300.0, 3000),
m(f"b-{tag}", 10, 50.0, 500)])
async with s.begin():
return await recent_usage(s, {(hid, f"a-{tag}")}, slots[0], width)
got = asyncio.run(go())
assert got == {(hid, f"a-{tag}"): {at: (200.0, 2000.0)}}