#5834 "The host agent is always on, and the MCP sees a host's maintenance", step 1 of milestone 520 "The MCP sees what Steward has grown". The host agent is a core system (operator, 2026-10-15: "it's very core to the functionality of Steward as a whole and shouldn't be considered something that can be toggled off"). ALWAYS_ON_PLUGINS in core settings makes to_plugins_cfg report it enabled whatever its stored row says, so it always loads and its MCP tools are always listed. Settings -> Plugins shows it as "Built in: always on" with no switch, and a save keeps it enabled. Its code and URLs stay under plugins/host_agent: every installed agent posts to /plugins/host_agent/ingest. Maintenance through the MCP: - list_maintenance_plans: each plan's group, weekly slot, reboot policy, next slot, and its latest run (hosts, how far it got, who it skipped and why, how it ended). - get_maintenance_job(host | job): a host's jobs, newest and running first, or one job: state, packages updated, reboot, drained by, why it failed, when its current state times out. - run_maintenance(host, reboot="if_required" | "never"): admin, as the host page's Update now; refuses a busy host or one with no helper; audited "<user> via MCP". - The overview names a host whose latest job in the last week failed or timed out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
55 lines
2.4 KiB
Python
55 lines
2.4 KiB
Python
"""Pure-function tests for the default-enabled plugin set.
|
|
|
|
A fresh install (no stored plugin.* rows) should come up with the generic,
|
|
non-vendor-specific bundled plugins already enabled, while vendor-specific
|
|
plugins stay opt-in. An operator's stored choice must override the default.
|
|
No DB / Quart fixtures — we exercise to_plugins_cfg over the DEFAULTS dict
|
|
and a DEFAULTS-merged-with-stored dict, mirroring get_all_settings' merge.
|
|
"""
|
|
from steward.core import settings as settings_module
|
|
from steward.core.settings import DEFAULTS, to_plugins_cfg
|
|
|
|
# NB: no "http" — that plugin was dissolved into the unified Monitor entity, and
|
|
# its lingering default is what test_plugin_settings_hygiene.py now guards against.
|
|
DEFAULT_ON = {"docker", "host_agent", "snmp"}
|
|
VENDOR_OPT_IN = {"traefik", "unifi"}
|
|
|
|
|
|
def test_generic_plugins_enabled_by_default():
|
|
cfg = to_plugins_cfg(DEFAULTS)
|
|
for name in DEFAULT_ON:
|
|
assert cfg.get(name, {}).get("enabled") is True, name
|
|
|
|
|
|
def test_vendor_plugins_not_enabled_by_default():
|
|
cfg = to_plugins_cfg(DEFAULTS)
|
|
for name in VENDOR_OPT_IN:
|
|
assert name not in cfg, name
|
|
|
|
|
|
def test_stored_choice_overrides_default():
|
|
# get_all_settings / load_settings_sync overlay stored values onto DEFAULTS;
|
|
# a stored disable must win over the built-in default-on.
|
|
merged = {**DEFAULTS, "plugin.docker": {"enabled": False}}
|
|
cfg = to_plugins_cfg(merged)
|
|
assert cfg["docker"]["enabled"] is False
|
|
# untouched defaults remain enabled
|
|
assert cfg["snmp"]["enabled"] is True
|
|
|
|
|
|
def test_defaults_use_plugin_dot_namespace():
|
|
# The keys must live under the plugin.<name> namespace to_plugins_cfg reads.
|
|
for name in DEFAULT_ON:
|
|
assert f"plugin.{name}" in settings_module.DEFAULTS
|
|
|
|
|
|
def test_the_host_agent_is_always_on():
|
|
"""Steward relies on it, so a stored disable, or no row at all, still
|
|
loads it (operator, 2026-10-15); its other settings are kept."""
|
|
stored_off = {**DEFAULTS, "plugin.host_agent": {"enabled": False, "stale_after_seconds": 300}}
|
|
assert to_plugins_cfg(stored_off)["host_agent"] == {"enabled": True, "stale_after_seconds": 300}
|
|
no_row = {k: v for k, v in DEFAULTS.items() if k != "plugin.host_agent"}
|
|
assert to_plugins_cfg(no_row)["host_agent"]["enabled"] is True
|
|
# Only the host agent: another plugin's stored disable still wins.
|
|
assert to_plugins_cfg({**DEFAULTS, "plugin.snmp": {"enabled": False}})["snmp"]["enabled"] is False
|