feat(alerts): renames carry their alerts — monitor and host renames move rules, windows and history (#5065)
#5065 "Renames carry their alerts". Alert rules, maintenance-window scopes and metric history key a thing by (source, name), so a rename used to leave the rules watching a name nothing reported under, and split the history. - core/renames.carry_rename moves AlertRule.resource_name, MaintenanceWindow.scope_resource, plugin_metrics and plugin_metrics_hourly to the new name in the caller's transaction. A host rename also carries its parts: host_agent "<host>:…" and docker "<host>/…" (HOST_SOURCES). Matching is exact (a prefix compare, not LIKE or a collation range). History left under the new name by something deleted is dropped first rather than merged in. - Web monitor edit, MCP update_monitor and web host edit call it; MCP answers with `carried` (it used to return a warning naming stranded rules). - A name another monitor of the same type, or another host, already has is refused on create and rename: two would share one history. - The rename is audited (monitor.updated / host.renamed) with what moved. Tests: an integration test renames a firing monitor through the web route and finds its rule still firing and cleared by a sample on the new name, its window and raw+hourly history moved and an orphan's history dropped; a host rename moves agent and container parts but not a longer-named host's or another source's; a guard that every host_agent resource is "<host>" or "<host>:…". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
"""Integration: the monitoring-config write tools against real Postgres.
|
||||
|
||||
A monitor is created on a host, edited (config merged, a rename warning for
|
||||
the rule that watches it by name), paused and deleted; a rule is created on
|
||||
A monitor is created on a host, edited (config merged, a rename that carries
|
||||
the rule watching it by name), paused and deleted; a rule is created on
|
||||
that monitor, edited, acknowledged once firing, and deleted; a maintenance
|
||||
window in progress is ended and an upcoming one cancelled. Every write leaves
|
||||
an audit row as "<user> via MCP".
|
||||
@@ -95,11 +95,15 @@ def test_monitor_rule_ack_and_maintenance_writes(app):
|
||||
row = await s.get(Monitor, made["monitor_id"])
|
||||
assert row.config["headers"] == {"Authorization": "Bearer s3cret"}
|
||||
|
||||
# A rename leaves the rule on the old name, and says so.
|
||||
# A rename takes the rule with it, and says what moved.
|
||||
renamed = await m.update_monitor(mon_name, name=f"{mon_name}-2")
|
||||
assert rule_name in renamed["warning"]
|
||||
await a.update_alert_rule(rule_name, resource=f"{mon_name}-2")
|
||||
assert "warning" not in await m.update_monitor(f"{mon_name}-2", check_interval_s=30)
|
||||
assert renamed["carried"]["from"] == mon_name and renamed["carried"]["rules"] == 1
|
||||
async with app.db_sessionmaker() as s:
|
||||
assert (await s.get(AlertRule, rule["rule_id"])).resource_name == f"{mon_name}-2"
|
||||
assert "carried" not in await m.update_monitor(f"{mon_name}-2", check_interval_s=30)
|
||||
# Another http monitor may not take the same name: they would share one history.
|
||||
with pytest.raises(ValueError, match="already named"):
|
||||
await m.create_monitor(f"{mon_name}-2", "http", "other.lan")
|
||||
assert (await m.set_monitor_enabled(f"{mon_name}-2", False))["enabled"] is False
|
||||
|
||||
# ── acknowledge ────────────────────────────────────────────────────
|
||||
|
||||
Reference in New Issue
Block a user