Files
claudetools/session-logs/2026-06-07-mike-gururmm-offline-alerting-mute.md
Mike Swanson b928fdb8f3 sync: auto-sync from GURU-5070 at 2026-06-07 17:45:03
Author: Mike Swanson
Machine: GURU-5070
Timestamp: 2026-06-07 17:45:03
2026-06-07 17:45:07 -07:00

14 KiB

GuruRMM — Role-Aware Offline Alerting + Alert Ignore/Mute (+ MSP360 API probe, Jupiter VM diag)

User

  • User: Mike Swanson (mike)
  • Machine: GURU-5070
  • Role: admin

Session Summary

Shipped two GuruRMM alerting features end-to-end and investigated an MSP360 API capability question, then diagnosed an unrelated Unraid VM network fault. After the morning backup-alert cleanup (separate log), Mike asked whether the MSP360 API could delete plans / trigger backups / configure storage for the three console follow-ups. Probed api.mspbackups.com with the vaulted Provider token: it is monitoring-only (Companies/Users/Monitoring, GET; every management path 404s; OPTIONS confirms read-only). The agent-CLI fallback also failed -- the white-labeled MSP360 agent on SERVER has no cbb.exe at any standard path. Concluded the three items stay MSP360-console tasks and filed them as coord todos for Mike.

Built role-aware offline alerting + correlated mass-offline detection (spec role-aware-offline-alerting). Servers offline are incidents; workstations offline are routine. Implemented server-side (Tasks 1-5): migration 054 role_override column + a shared agent_role classifier delegating to the canonical agent_is_server; OfflineAlertingConfig in the policy JSONB; a new scheduled offline-sweep evaluator generating server-only agent_offline alerts plus site (>=50% + >=3) and fleet (>=10) mass_offline_* aggregates; a warm-up restart guard; and PUT /api/agents/:id/role-override. Code Review REJECTED the first cut for a CRITICAL defect in the spec's own restart guard (last_seen < started_at permanently disabled detection in steady state because last_seen advances on every heartbeat); fixed by making the warm-up window the sole guard. Re-review APPROVED. Then the dashboard unit (Tasks 6-7): role-aware triage (offline servers individual + elevated; offline workstations collapsed into a quiet "N workstations offline" roll-up) and the role-override control on the agent detail page; plus a small server DTO fix so GET /api/agents/:id returns role_override. Verified live: a real offline server (WIN-TG2STMODJG8, "Windows Server 2019 Standard Evaluation", auto-classified via os_name) fired agent_offline; zero false mass-offline despite ~55 chronically-offline agents; restart guard held across deploys.

Built alert ignore/mute (perma-silence) (spec alert-mute). Distinct from ack/resolve, which only quiet the current cycle: a mute keyed on dedup_key suppresses a recurring condition until un-ignored, with a required reason. Server unit (Tasks 1-4): migration 055 alert_mutes table + muted status; an is_dedup_muted gate inserted into the universal create_or_update_alert AND the one create_check_alert bypass so muted conditions write status='muted' (never active, never email); transactional mute_condition/unmute_condition; POST /api/alerts/:id/mute (reason required -> 400) and /unmute. Code Review APPROVED (the muted gate is a top-of-function early return, so the active path is byte-for-byte unchanged for normal alerts). Verified live against WIN-TG2STMODJG8's re-firing agent_offline: mute -> muted, survived a full offline sweep without re-firing, unmute -> active. The dashboard unit (Task 5) is NOT yet built.

Finally, diagnosed an Unraid VM network fault on Jupiter (172.16.3.20): the libvirt domain "Windows Server 2016" (guest hostname ACG-DWP-X-BB) had no LAN. Found the host side healthy (vnet8 bridged to br0, forwarding, receiving LAN broadcast), and the guest holding APIPA 169.254.157.152 with no gateway -- its single e1000 NIC is DHCP-enabled but not getting a lease from pfSense (172.16.0.1). Paused for Mike's call on DHCP-vs-static before changing the guest.

Key Decisions

  • Offline classification = auto (os_product_type 2/3, else os_name/os_version ~/server/i) + a manual role_override column. os_product_type is populated on only 16/168 agents, so os_name is the workhorse signal; inventory-less offline servers (SIF-SERVER, Server2013) auto-classify as workstations and need the manual override -- Mike held on tagging them.
  • Mass/aggregate alerts pin to a representative offline agent with a site/fleet dedup_key rather than making alerts.agent_id nullable (avoids a rippling migration across every alert path).
  • Restart guard = warm-up window only (max grace after boot). Dropped the broken last_seen < started_at clause. Individual server alerts fire independently of the site-outage alert (so a still-down server keeps paging after an outage clears).
  • Alert mute keyed on dedup_key (universal recurring-condition id, always set); permanent until un-ignored; stays muted on severity escalation. Gate placed at the two creation choke points so it is universal across every alert type.
  • MSP360 console items stay manual: the Provider API token is monitoring-tier only; no REST path for plan delete / run / storage config at our access level.

Problems Encountered

  • CRITICAL restart-guard defect (my spec error): last_seen < started_at silently disabled offline detection in steady state. Caught in Code Review; fixed to warm-up-only and re-reviewed. The bug-enshrining unit test was rewritten.
  • Split-brain classifier: the new agent_role diverged from the existing agent_is_server. Unified by delegating to the canonical fn (threaded os_version).
  • GET /api/agents/:id omitted role_override (returns AgentResponse, not AgentWithDetails), so the override card rendered blind. Fixed by adding the field to the base Agent/AgentResponse DTOs (all Agent SELECTs use SELECT *).
  • Orphaned offline alerts + per-agent policy N+1 in the sweep: replaced scattered resolves with one authoritative resolve-except pass; read per-agent grace only for servers; mass membership uses global grace/window.
  • MSP360 white-label: no cbb.exe on SERVER, so the agent-CLI automation route for the backup console tasks was not viable without per-box fingerprinting.
  • Submodule gitlink: detached to the pinned commit before /save so the session-log commit does not fold a gitlink bump.

Configuration Changes

GuruRMM submodule (azcomputerguru/gururmm), all merged to main:

  • server/migrations/054_agent_role_override.sql (new) -- role_override column.
  • server/migrations/055_alert_mutes.sql (new) -- alert_mutes table + partial unique index ON dedup_key WHERE active.
  • server/src/alerts/offline.rs (new) -- offline sweep + mass detection.
  • server/src/db/alerts.rs -- AlertStatus::Muted; is_dedup_muted/ mute_condition/unmute_condition; muted gate in create_or_update_alert; create_or_update_alert title/message/severity refresh (from morning).
  • server/src/alerts/check_alerts.rs -- mute gate + notify suppression.
  • server/src/db/agents.rs -- role_override on Agent/AgentResponse/ AgentWithDetails; agent_role + set_agent_role_override.
  • server/src/db/policies.rs, server/src/policy/{effective,merge}.rs -- OfflineAlertingConfig + merge.
  • server/src/main.rs -- offline-sweep spawn (60s).
  • server/src/api/{alerts,agents,mod}.rs -- mute/unmute + role-override endpoints.
  • dashboard/src/lib/agentRole.ts (new), dashboard/src/components/ExceptionStream.tsx, dashboard/src/pages/AgentDetail.tsx, dashboard/src/api/client.ts -- triage + override control.
  • specs/role-aware-offline-alerting/ and specs/alert-mute/ (new spec folders).

Credentials & Secrets

No new secrets. MSP360 Provider API: vault msp-tools/msp360-api.sops.yaml (credentials.login / credentials.password); base https://api.mspbackups.com, POST /api/Provider/Login -> access_token; monitoring-only tier. GuruRMM API: vault infrastructure/gururmm-server.sops.yaml. Jupiter: vault infrastructure/jupiter-unraid-primary.sops.yaml (root@172.16.3.20:22, key auth works from GURU-5070).

Infrastructure & Servers

  • GuruRMM API/server: 172.16.3.30:3001 (Linux VM on Jupiter). Dashboards rmm-beta / rmm.azcomputerguru.com (shared API serves both).
  • Jupiter Unraid: 172.16.3.20, root:22, Unraid 6.12.85. VMs via virsh; bridge br0 (uplink eth2), 172.16.3.20/22. VM "Windows Server 2016" = guest ACG-DWP-X-BB, vnet8/br0/e1000, MAC 52:54:00:d4:8e:59, APIPA 169.254.157.152 (no DHCP lease).
  • Office LAN 172.16.0.0/22; pfSense 172.16.0.1 (router + DNS + DHCP).

Commands & Outputs

  • Offline alerting commits: f1cdf5d, 30e4f23 (fix), 21d63bd (DTO), 3eedf91 (dashboard). Alert-mute: 29c405e (spec), a120e71 (server).
  • Live mute verify: empty-reason 400; mute -> status=muted; after a 60s sweep the muted alert did NOT re-fire active (count=0); unmute -> active.
  • Jupiter diag: virsh domiflist 9 (vnet8/br0/e1000); virsh domifaddr 9 --source agent -> 169.254.157.152; guest-exec ipconfig /all -> DHCP Enabled: Yes, APIPA, no gateway.

Pending / Incomplete Tasks

  • alert-mute dashboard (Task 5) -- NOT started. Ignore button + required-reason prompt + Muted filter + Un-ignore, on the alerts page AND the agent Alerts tab; muted rows show Un-ignore instead of Ack/Resolve. (Mike: "then continue" -> do this next.) Plus alert-mute Task 6 (roadmap) + Task 7 (final doc).
  • offline alerting -- Task 8 (roadmap entry) outstanding; classification gap: tag SIF-SERVER / Server2013 (and WIN-TG2STMODJG8 if it should be a workstation) via role_override -- held for Mike.
  • Jupiter VM -- decide DHCP vs static for ACG-DWP-X-BB; if DHCP, run ipconfig /renew via guest agent; if static, set the intended IP. Paused for Mike.
  • MSP360 console (Mike-side todos): delete SERVER's Nov-2024 plan; AD1 full backup for retention; LAB-Becky storage-or-delete.

Reference Information

  • Commits (main): f1cdf5d,30e4f23,21d63bd,3eedf91,29c405e,a120e71.
  • Specs: projects/msp-tools/guru-rmm/specs/role-aware-offline-alerting/, .../specs/alert-mute/.
  • MSP360 PlanType map: 3=Files,7=SQL,8=Restore,11=Image,13=Consistency,16=HyperV.
  • New alert types: agent_offline, mass_offline_site, mass_offline_fleet; new status muted; new tables alert_mutes; new columns agents.role_override.
  • Test box: WIN-TG2STMODJG8 agent id b6c715df-09fe-4e97-b09a-82a1b535f041 (offline eval server, used for live verification).

Update: 00:44 PT — alert-mute dashboard shipped, beta->prod promotion, MSI dedup cleanup, parked design

Completed since the initial save

  • Alert ignore/mute dashboard (Task 5) — shipped + deployed (commit 63d7c5d). Reused the existing Radix Dialog for the required-reason prompt; shared AlertRow so both the alerts page and the agent Alerts tab get Ignore/Un-ignore + the Muted filter; muted rows show Un-ignore (not Ack/Resolve) + reason/who/when; status badge labels muted as "Ignored". Code Review APPROVED; npm run build clean. The alert-mute feature is now complete end-to-end (server a120e71 + dashboard 63d7c5d).
  • Roadmap entries (commit 5f1d9f0): both offline alerting and alert ignore/mute added to FEATURE_ROADMAP.md Alerting section; specs' roadmap tasks marked DONE.
  • Dashboard beta -> production promotion. Prod (/var/www/gururmm/dashboard, rmm.azcomputerguru.com) was stuck at the 2026-06-04 build. Ran sudo /opt/gururmm/promote-dashboard.sh --confirm on 172.16.3.30 (the sanctioned promote: backs up prod first, keeps 10 backups, rsync beta->prod, --rollback to undo). Backup dashboard-20260608-000926; prod now byte-identical to beta. This shipped ALL accumulated beta work to prod: this session's offline triage + role-override + alert mute UI, plus other sessions' credential-inheritance mgmt + clickable alert badges. Coord component gururmm/dashboard -> deployed.
  • MSI BSOD duplicate cleanup. MSI (Safesite/Glendale, agent a685af29...) had 4 BSOD VIDEO_TDR_FAILURE (0x116) alerts, all with dedup_key = NULL (legacy, from the early-June BSOD implementation before the dedup key was added). Mike had muted one; the other 3 active duplicates could not be spanned by the mute (NULL key falls back to single-row). Resolved the 3 duplicates (final: 0 active, 1 muted "Client to replace unit", 3 resolved). Two resolve calls hit transient HTTP 000; retried clean.

Parked design conversation (NOT approved — captured for later)

A stream-of-thought design discussion produced two parked features, captured in projects/msp-tools/guru-rmm/docs/PARKED_alert-lifecycle-and-telemetry-cadence.md (commit 82a7b14) + two coord todos (eb14a4d2, bacc4f12):

  1. Stateful alert lifecycle + occurrence history (server): one alert per dedup_key spanning all statuses; re-fire reopens only when "substantively different" (severity escalation or re-fire after clear; not per-1%); occurrence count+first/last on the row, dated history via existing agent_events (no new table); ack reopens on substantive change, mute is absolute; server-side per-condition cooldown (~15min default, escalations bypass, recovery always prompt); subsumes BSOD per-bugcheck dedup + mute-across-refire + legacy null-key cleanup. Root cause it fixes: dedup currently matches only status='active', so ack/resolve breaks dedup and spawns duplicates.
  2. Tiered agent telemetry cadence (agent): per-collector collection intervals (live/on-demand ~5-10s only when watched; standard ~30-60s; slow ~5-15min; daily). Disk consumption (slow) vs disk I/O (fast) are different collectors; fast diagnostics as on-demand/live mode; cadence config in policy, server-pushed; cross-platform scheduler. Larger, separate agent-side feature.

Saved a feedback memory (.claude/memory/feedback_stream_of_thought_design.md): Mike prefers free-form design conversations; Claude sharpens as a design partner but does not build until an explicit go, then decomposes into specs.

Still open / parked

  • Jupiter VM ACG-DWP-X-BB no-DHCP (diagnosed, paused for Mike's DHCP-vs-static call; see wiki/systems/jupiter.md).
  • Offline classification overrides (SIF-SERVER/Server2013/WIN-TG2STMODJG8) — taggable from the agent detail role-override control; held.
  • The two parked design features above; MSP360 console todos (3) from the morning.