# plugins/host_agent/__init__.py from __future__ import annotations from typing import TYPE_CHECKING if TYPE_CHECKING: from quart import Quart _app: "Quart | None" = None def setup(app: "Quart") -> None: global _app _app = app # A host's CPU, memory and load per core learn their normal (#5742), each # with its floor from Settings → Thresholds. Parts don't: a host's CPU has # a normal, each of its cores doesn't. Disks stay on their fixed cutoffs: # a nearly full disk is a failure whatever its history (System 182). from steward.core.norms import floor_setting, learn_normal learn_normal("host_agent", "cpu_pct", floor_setting(app, "host_cpu_pct"), parts=False) learn_normal("host_agent", "mem_used_pct", floor_setting(app, "host_mem_pct"), parts=False) learn_normal("host_agent", "load_pct", floor_setting(app, "host_load_pct"), parts=False) # "Agent offline" speaks for everything the agent carries: while it is # firing, the host's other rules going silent isn't emailed (#5721). from steward.core.alerts import agent_fed, agent_heartbeat from steward.hosts.service import agent_stale_after_seconds agent_heartbeat("host_agent", "seconds_since_seen", lambda: agent_stale_after_seconds(app.config)) agent_fed("host_agent", lambda resource: resource.split(":", 1)[0]) # A reboot the agent announced is silence with a reason, for a while (#5756). from datetime import datetime, timezone from steward.core.alerts import agents_away from .downtime import hosts_away, restart_grace_seconds agents_away(lambda session: hosts_away(session, datetime.now(timezone.utc), restart_grace_seconds(app.config))) from steward.core.cleanup import prune_by_age from .models import HostDowntime prune_by_age(HostDowntime.started_at) def get_scheduled_tasks() -> list: from .scheduler import make_task return [make_task(_app)] def get_blueprint(): from .routes import host_agent_bp return host_agent_bp def register_mcp_tools(register) -> None: from .mcp_tools import register_tools register_tools(register) async def mcp_overview(db) -> list[dict]: from .mcp_tools import mcp_overview as findings return await findings(db) def get_alert_metrics() -> dict[str, list[str]]: """Host metrics ingest records for alert rules (resource = the host name; disk_used_pct per mount, resource ":"). seconds_since_seen comes from the scheduler, not the agent: "agent offline" is > 180. clock_off_secs is how far the host's clock is from Steward's, either way (agent ≥ 1.12.0): "clock drifting" is > 30. load_pct is load_1m as a % of the host's cores. inodes_used_pct is per mount (agent ≥ 1.13.0), and disk_used_pct_worst is the fullest mount by space or inodes.""" return {"host_agent": [ "cpu_pct", "mem_used_pct", "mem_available_bytes", "swap_used_bytes", "disk_used_pct_worst", "disk_used_pct", "inodes_used_pct", "load_1m", "load_5m", "load_15m", "load_pct", "uptime_secs", "seconds_since_seen", "clock_off_secs", ]}