feat(host_agent): a reboot reads as a reboot, and lost contact as its span (#5756)
#5756 "The agent says when its host rebooted and when it lost contact, so downtime is recorded as what it was". Agent 1.14.0 posts events with the next post that gets through: started (with the host's boot time), stopping (on SIGTERM, with whether systemd says the host is going down) and lost_contact (from its first unanswered post to the one carrying it). Steward keeps them as the host's downtime (host_downtime): reboot, agent_stop, unclean (a boot after the agent was last heard that nobody announced) or lost_contact. Retried posts apply once. An announced stop explains the silence for reboot_grace_seconds (Settings -> Plugins -> host_agent, 10 minutes): seconds_since_seen reads 0 until then, and the host's other rules go quiet with it (agents_away beside #5721's registry). Past the grace, agent offline fires. The host's Agent card lists the last 7 days of downtime. Rows are pruned at data.retention_days. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -208,3 +208,30 @@ def test_sort_hosts_puts_missing_values_last_either_way():
|
||||
assert names("cpu", False) == ["alpha", "bravo", "charlie"] # no reading: last both ways
|
||||
assert names("name", True) == ["charlie", "bravo", "alpha"]
|
||||
assert names("status", False)[0] == "charlie" # down first
|
||||
|
||||
|
||||
async def test_the_agent_card_says_what_happened_while_the_host_was_away(app):
|
||||
"""#5756: a reboot reads as a reboot with its length, one still going says so."""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from tests._templates import render_plugin_template
|
||||
now = datetime.now(timezone.utc)
|
||||
host = SimpleNamespace(id="h1", name="box", address="10.0.0.5")
|
||||
reg = SimpleNamespace(agent_version="1.14.0", last_seen_at=now)
|
||||
downtime = [
|
||||
{"kind": "reboot", "label": "Rebooted", "started_at": now - timedelta(minutes=5),
|
||||
"ended_at": None, "ongoing": True, "seconds": 300.0},
|
||||
{"kind": "lost_contact", "label": "Lost contact", "started_at": now - timedelta(hours=3),
|
||||
"ended_at": now - timedelta(hours=2), "ongoing": False, "seconds": 3600.0},
|
||||
]
|
||||
async with app.test_request_context("/plugins/host_agent/panel/h1"):
|
||||
session["user_role"] = "viewer"
|
||||
page = await render_plugin_template(
|
||||
app, "host_agent", "panel.html", host=host, reg=reg, reporting=True, stale=False,
|
||||
target=None, ansible_available=False, managed_key_set=False, downtime=downtime)
|
||||
quiet = await render_plugin_template(
|
||||
app, "host_agent", "panel.html", host=host, reg=reg, reporting=True, stale=False,
|
||||
target=None, ansible_available=False, managed_key_set=False, downtime=[])
|
||||
assert "Downtime, last 7 days" in page
|
||||
assert page.index("Rebooted") < page.index("Lost contact")
|
||||
assert "going on, 5m" in page and "1h" in page
|
||||
assert "Downtime, last 7 days" not in quiet
|
||||
|
||||
Reference in New Issue
Block a user