Server-side RMM telemetry plugin: current-snapshot endpointstates plus append-only curated endpointevents, resolved to existing Computer assets by hostname. Adds ADR-010 asset panels (status, services, recent events), dashboard quiet and stability cards, and a minimal Fleet list view that links into existing PC detail pages. Registers the activity sidebar icon and a dev-only sample seeder. Ingest arrives on the generic collector route; the future C# agent design record lives in docs/DESIGN-DECISIONS-agent.md.
156 lines
8.4 KiB
Markdown
156 lines
8.4 KiB
Markdown
# Agent Design Decisions (running preference list)
|
|
|
|
Server-side decisions made while building the `endpoints` plugin that the
|
|
future C# agent (and the ServiceNow ticketing surface) must honor. This is a
|
|
living document: add to it as the agent build raises questions. ASCII only, no
|
|
em-dashes, no emojis, per repo style.
|
|
|
|
## Scope of this document
|
|
|
|
The `endpoints` plugin (server) is the authoritative contract. The C# agent is
|
|
a separate deliverable in its own solution/repo. Anything the agent sends must
|
|
match what this plugin ingests; when the two disagree, this plugin wins and the
|
|
agent changes.
|
|
|
|
## 1. Transport and identity
|
|
|
|
- Agent posts one JSON object per host to `POST /api/collector/endpoints`
|
|
(the generic ADR-006 collector route, auto-registered by the core loader).
|
|
- Auth is a collector-scoped credential in the request HEADER, not a user JWT
|
|
and not a querystring. Server reads `COLLECTOR_API_KEY_ENDPOINTS` first, then
|
|
falls back to `COLLECTOR_API_KEY`. Provision the key the same way the
|
|
computers reporter does: out of band, e.g. `HKLM:\SOFTWARE\GE\ShopDB
|
|
CollectorKey`. The key is never baked into a distributed script/binary.
|
|
- Identity field is `hostname` (case-insensitive). The server resolves it to an
|
|
existing computer asset via the `computers` plugin. An unknown hostname is
|
|
REJECTED with a validation error, never auto-created. Decision: the fleet is
|
|
provisioned in ShopDB first (imports/Azure device sync); the agent does not
|
|
get to invent assets. Revisit only if bulk self-registration becomes a need.
|
|
|
|
## 2. Report shape (current server contract)
|
|
|
|
Top-level payload fields the server currently reads (see
|
|
`plugins/endpoints/plugin.py` `get_collector_schema`):
|
|
|
|
- `hostname` (required), `loggedinuser`, `agentversion`
|
|
- Metrics: `lastboottime` (ISO-8601), `uptimeseconds`, `idleseconds`,
|
|
`cpupercent`, `memorypercent`
|
|
- Inventory arrays (stored as latest-snapshot JSON, not history):
|
|
`services`, `ports`, `interfaces`, `scheduledtasks`
|
|
- `events`: array of curated Windows Event Log records (see section 4)
|
|
|
|
Decision: inventory and metrics are a SNAPSHOT overwrite (one `EndpointState`
|
|
row per asset), not time-series. The agent sends the full current list each
|
|
cycle; the server does not diff or version them. If per-sample history is later
|
|
required, it goes in a new append-only table and the contract stays additive.
|
|
|
|
## 3. Reporting rhythm
|
|
|
|
- Default report interval: 15 minutes (`report_interval_minutes` in the plugin
|
|
manifest settings; a site setting can override). Agent design should make the
|
|
interval configurable and jittered to avoid a fleet-wide thundering herd.
|
|
- There is NO separate heartbeat. `lastreportedat` is stamped on every report;
|
|
"quiet" endpoints are those past the quiet-report window (default 24h, site
|
|
setting `endpoints_quietreporthours`). Agent does not need a distinct ping.
|
|
|
|
## 4. Curated Windows Event catalog (LOCKED to the server list)
|
|
|
|
The server stores ONLY these IDs; anything else in `events` is ignored (not an
|
|
error). Source of truth: `CURATED_EVENT_IDS` in `plugins/endpoints/plugin.py`.
|
|
|
|
| Event ID | Channel | Meaning |
|
|
|----------|--------------|--------------------------------------------|
|
|
| 4624 | Security | Successful logon |
|
|
| 4625 | Security | Failed logon |
|
|
| 4634 | Security | Logoff |
|
|
| 4672 | Security | Special privileges assigned to new logon |
|
|
| 4697 | Security | Service installed |
|
|
| 4698 | Security | Scheduled task created |
|
|
| 41 | System | Kernel-Power, unexpected shutdown |
|
|
| 4618 | Security | Monitored security event pattern |
|
|
| 55 | System | NTFS file system corruption |
|
|
| 7011 | System | Service Control Manager timeout |
|
|
| 10016 | System | DCOM permission error |
|
|
| 1001 | Application | Application error / bugcheck report |
|
|
|
|
- Per event, the agent sends: `eventid` (required), `eventchannel`,
|
|
`eventsource`, `eventtime` (ISO-8601, event time not report time),
|
|
`eventmessage`, and `fields` (an object of extracted structured values, e.g.
|
|
target account on a 4625). `fields` is stored as `payloadjson`.
|
|
- OPEN QUESTION for the agent build: which IDs need structured `fields` parsing
|
|
vs. raw message pass-through. Start with pass-through message; add structured
|
|
parsing per ID as alerting rules demand it. The teammate flagged event parsing
|
|
as the hard part; keep the catalog fixed and small until baselined.
|
|
- Scheduled-task history being disabled on some hosts means 4698 and task
|
|
"last run" may be sparse; the agent should read current task state directly,
|
|
not rely on event history alone.
|
|
|
|
## 5. Monitored services/processes
|
|
|
|
Known targets to watch (non-exhaustive, confirm during agent build): UDC, eDnc,
|
|
Intune-related services. Server stores whatever list the agent sends in
|
|
`servicesjson` without a fixed schema yet. Decision deferred: once the watched
|
|
set is final, consider promoting it to a server-known enum for alerting.
|
|
|
|
## 6. ServiceNow ticketing surface (future, creds confirmed available)
|
|
|
|
Not built server-side yet. Recorded here so the agent and a future server
|
|
endpoint agree:
|
|
|
|
- Interactive C# piece (system-tray/desktop launcher) owns the 5-click-max flow:
|
|
network precheck -> issue dropdown -> optional screenshot -> submit.
|
|
- Fixed dropdown reasons (from the source conversation): Can't logon to CSF;
|
|
Data collections down; Can't download program; Machine communication failing;
|
|
Network drives down; Other (free text).
|
|
- Screenshot saved to local `Pictures\Screenshots` before submission.
|
|
- OPEN: whether ticket submission goes direct to the ServiceNow API from the
|
|
agent, or is proxied through a ShopDB server endpoint (preferred: proxy, so
|
|
ServiceNow creds live server-side and the agent carries only its collector
|
|
key). Decide before wiring the integration.
|
|
|
|
## 7. Runtime split (from the planning conversation)
|
|
|
|
- Interactive bits (tray launcher, ticketing, screenshot): C# / .NET, likely a
|
|
Windows service + tray app.
|
|
- Collections MAY be locally hosted PowerShell scripts the service invokes,
|
|
where that is simpler than reimplementing WMI/CIM queries in C#.
|
|
- Code signing and Intune deployment are agent-side concerns, out of scope for
|
|
the server plugin but must be planned before fleet rollout.
|
|
|
|
## 8. Web UI display (server-side, built)
|
|
|
|
The collected data surfaces through ShopDB's existing declaration-driven UI
|
|
contract (ADR-010). The plugin declares WHAT to show; generic core components
|
|
render it. No plugin-specific Vue components were written. Audience is DT
|
|
support / IT, NOT the shop-floor operator (the operator's surface is the
|
|
agent-side ticket tool).
|
|
|
|
Surfaces implemented:
|
|
|
|
- Per-PC asset panels (computer assets only), on the PC detail page:
|
|
- Endpoint status (keyvalue): logged-in user, uptime, idle, last boot,
|
|
CPU/memory %, agent version, last reported. Feeds
|
|
`GET /api/endpoints/asset/{assetid}/status`.
|
|
- Services and processes (list + badge): monitored services with a green/red
|
|
run-state badge. Feeds `.../services`.
|
|
- Recent events (list + severity badge): last 10 curated events. Feeds
|
|
`.../recentevents`.
|
|
- Dashboard exception cards (hide when empty):
|
|
- Endpoints gone quiet (warning): `.../dashboard/quiet`.
|
|
- Endpoints with crashes or shutdowns (critical): `.../dashboard/stability`,
|
|
bounded to a 48h window and the critical event catalog.
|
|
|
|
DECISION - freshness and cost. There is NO live streaming and NO polling. The
|
|
freshness ceiling is the agent report cadence (~15 min), so a websocket/poll
|
|
buys nothing but load. Data is fetched on page/dashboard load only, matching the
|
|
existing computers-quiet card. Asset panels are single-asset indexed reads
|
|
(negligible). Dashboard cards run once per dashboard load, cap at 50 rows, and
|
|
the stability card is time-bounded so it does not grow with total history. If
|
|
fleet-wide aggregation ever gets heavy, memoize dashboard aggregates with the
|
|
core `cache` helper for ~60s - documented lever, not built yet.
|
|
|
|
Agent implication: the agent does not drive any UI refresh. Its only job is to
|
|
report on its rhythm; the UI reflects whatever the last report wrote. The
|
|
`services` payload should send a per-service run STATE (e.g. running/stopped) so
|
|
the badge can color it; a missing/unknown state renders as a gray Unknown badge.
|