feat(docker): Services & Failures widget lists what is wrong, then packs the healthy (#5252)
A verdict line (services healthy · other containers running · failed in 24h), then "Needs a look": troubled services with why (crash-looping, N of M running), since when and the last error, and troubled containers (unhealthy, restarting, exited with an error, out of memory). Then "Failed in the last 24h" by name, with how often, when and where. Then the healthy rest one line each (name · hosts · replicas) in as many columns as the widget is wide, collapsing after 40 to "+N more healthy". Per-container CPU is gone from this widget: Busiest Containers owns it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -162,3 +162,49 @@ async def test_the_disk_page_explains_its_terms_and_names_untagged_images(app):
|
||||
assert "held by images no container uses" in page and "safe to clear" in page
|
||||
assert "Shared with other images" in page and "2 containers" in page and ">nothing<" in page
|
||||
assert "dangling" not in page
|
||||
|
||||
|
||||
def _widget_svc(name, state="healthy", running=1, desired=1, hosts=("VDNT-Docker02",), **kw):
|
||||
base = dict(name=name, state=state, running=running, desired=desired, crash_looping=False,
|
||||
failures_1h=0, last_error=None, trouble_since=None,
|
||||
replicas=[{"host": h, "ghost": False} for h in hosts])
|
||||
base.update(kw)
|
||||
return base
|
||||
|
||||
|
||||
async def _services_widget(app, **ctx):
|
||||
base = dict(bad_services=[], bad_containers=[], healthy=[], healthy_more=0, services_total=0,
|
||||
services_healthy=0, running_count=0, failures=[], host_name={"h1": "VDNT-Docker02"},
|
||||
total_count=1, widget_id="1")
|
||||
base.update(ctx)
|
||||
async with app.test_request_context("/plugins/docker/widget"):
|
||||
return await render_plugin_template(app, "docker", "docker/widget.html", **base)
|
||||
|
||||
|
||||
async def test_the_services_widget_lists_what_is_wrong_then_packs_the_healthy(app):
|
||||
"""#5252: a verdict, the troubled service with why and since when, the
|
||||
failures by name, then healthy services one line each in a packed grid."""
|
||||
bad = _widget_svc("codex_db", state="down", running=0, crash_looping=True, failures_1h=7,
|
||||
trouble_since=datetime.now(timezone.utc) - timedelta(minutes=9))
|
||||
page = await _services_widget(
|
||||
app, bad_services=[bad], services_total=3, services_healthy=2, running_count=4,
|
||||
failures=[{"name": "codex_db", "host": "VDNT-Docker03", "count": 7, "at": NOW - timedelta(minutes=1),
|
||||
"detail": "exit 1"}],
|
||||
healthy=[{"kind": "service", "s": _widget_svc("curator_app")},
|
||||
{"kind": "service", "s": _widget_svc("web", running=2, desired=2, hosts=("a", "b", "a"))},
|
||||
{"kind": "container", "c": _c("portainer_agent")}],
|
||||
healthy_more=12)
|
||||
assert "2/3 services healthy" in page and "4 other containers running" in page and "1 failed in 24h" in page
|
||||
assert page.index("Needs a look") < page.index("Failed in the last 24h") < page.index("Healthy")
|
||||
assert "crash-looping: 7 failed in the last hour" in page and "9m ago" in page
|
||||
assert "7 times, last" in page and "exit 1" in page
|
||||
assert 'class="w-grid"' in page and " · a, b</span>" in page and ">2/2<" in page
|
||||
assert "+12 more healthy" in page
|
||||
assert not hex_colours(page), hex_colours(page)
|
||||
|
||||
|
||||
async def test_the_services_widget_says_when_all_is_well(app):
|
||||
page = await _services_widget(app, services_total=2, services_healthy=2, running_count=1,
|
||||
healthy=[{"kind": "service", "s": _widget_svc("a")}])
|
||||
assert "2/2 services healthy" in page and "nothing failed in 24h" in page and "tone-ok" in page
|
||||
assert "Needs a look" not in page and "Failed in the last 24h" not in page
|
||||
|
||||
Reference in New Issue
Block a user