Skip to content

ADR discovery

Pola, Sudhir edited this page Apr 27, 2026 · 6 revisions

ADR: DMT Device Discovery & Observability

Status: Proposed

Context

Operators of AMT-capable device fleets currently have limited visibility into device firmware state, OS environment, and key service presence (such as Intel LMS) as captured in the following three feature requests which require a unified solution:

  • sample-web-ui#1265 — Display SKU type (vPro / ISM / Non-vPro) and Configuration mode (ACM / CCM / Pre-Prov) in the Devices UI. The data exists in deviceInfo as raw numbers but is not decoded or displayed.
  • console#858 — Add a lightweight discovery agent that collects AMT/ME and OS platform details from unmanaged and managed devices and reports them back to Console for dashboard display, filtering, and export.
  • rpc-go#1246 — Detect whether Intel LMS is installed during the v3 orchestration flow and persist that flag in Console.

The current data model does not store many of the required fields (TLS mode, UPID, LMS state, OS details, adapter count, monitor presence). Existing write paths (RPS activation, rpc amtinfo --sync) need to be extended, and a new persistent discovery agent is needed.

Decision

1. Data Model

Extend deviceInfo JSON (both MPS and Console) with AMT/ME firmware fields:

Field Type
tlsMode string
upid string
amtEnabledInBIOS boolean
meInterfaceVersion string
dhcpEnabled boolean
certHashes string[]

Introduce a new discoveryInfo JSON column (Console only) for OS and platform state:

Field Type
lmsInstalled boolean
lmsVersion string
osName / osVersion / osDistro string
cpuModel string
osIpAddress string
ethernetAdapterCount int
monitorConnected boolean
ieee8021xEnabled boolean
lastDiscovered timestamp

LMS state from rpc-go#1246 is stored in discoveryInfo.lmsInstalled (not deviceInfo). The discoveryInfo column accepts partial writes at registration time so that lmsInstalled is captured immediately, even for devices that never undergo a full discovery scan.

2. API Changes

Nine API changes are required across Console and rpc-go:

# Endpoint Service Change
1 POST /api/v1/devices Console Accept isLMSAvailable; write to discoveryInfo.lmsInstalled
2 POST /api/v1/devices/discovery Console New — discovery agent report endpoint
3 GET /api/v1/devices[/:guid] Console Include discoveryInfo in response
4 GET /api/v1/devices Console Add filter/sort query parameters
5 GET /api/v1/devices/export Console New — CSV/JSON export
6 PATCH /api/v1/devices Console + MPS Extend deviceInfo accepted fields
7 PATCH /api/v1/devices Console Accept discoveryInfo partial payload
8 rpc amtinfo --sync payload rpc-go Extend syncDeviceInfo; add discoveryInfo struct
9 Registration payloads rpc-go Add IsLMSAvailable to DevicePayload; add LmsInstalled to MessagePayload

3. Discovery Agent Architecture

A new standalone binary, rpc-discovery, is introduced. It runs as a long-lived background service (Windows SCM / Linux systemd) and invokes the rpc binary as a subprocess for AMT data collection.

rpc-discovery (new binary)
  ├── service harness (kardianos/service)
  ├── scheduler (periodic scan interval)
  ├── AMT collector   → shells out: rpc amtinfo --all --json
  │                                 rpc amtinfo --sync --url <console>/api/v1/devices
  ├── OS collector    (new Go code: LMS probe, OS details, adapters, monitor)
  └── Console reporter → POST <console>/api/v1/devices/discovery (Bearer JWT)

rpc-discovery is co-deployed alongside the rpc binary on the device. It does not import rpc-go packages.

4. Agent Distribution

Console exposes two download endpoints:

Endpoint Purpose
GET /api/v1/discovery/agent?platform=windows|linux Serve the rpc-discovery binary as an application/octet-stream download
GET /api/v1/discovery/agent/config Serve a per-request signed agent-config.yaml containing the Console URL and scoped JWT

The operator downloads the binary and config separately (both endpoints require authentication), then deploys them together onto the device. Console stores the binary as a static asset (checksummed and optionally code-signed) and generates the config on demand — no bundling or server-side archive assembly is required.

The agent configuration file:

consoleURL: https://console.example.com
token: <scoped-JWT>
reportInterval: 3600   # seconds
skipCertCheck: false

Alternatives Considered

Alternative 1 — Store LMS in deviceInfo instead of discoveryInfo

The issue author targets the "device information table", which maps naturally to deviceInfo. However, LMS is an OS-level service, not an AMT/ME firmware concept. Splitting lmsInstalled into deviceInfo and lmsVersion into discoveryInfo would divide related LMS state across two blobs. Storing both in discoveryInfo with partial writes at registration is cleaner.

Rejected. All LMS state is stored in discoveryInfo.

Alternative 2 — Add rpc agent subcommand to rpc-go (Approach B)

Add an agent subcommand to the existing rpc binary so a single binary handles both CLI and background-service modes.

Pros: single binary, no additional artifact. Cons: rpc-go is already used as a DLL via go build -buildmode=c-shared. Embedding a persistent Windows SCM / systemd service harness in the same binary is architecturally risky. The short-lived CLI lifecycle conflicts with long-running service signal handling.

Rejected for production. Acceptable only as a short-term prototype if the agent command is compiled out of the DLL build target.

Alternative 3 — Embed rpc-go packages in rpc-discovery directly

Import internal/device, internal/commands/amtinfo, and internal/lm packages from rpc-go into the rpc-discovery binary at build time.

Pros: no subprocess overhead; single process. Cons: creates a build-time coupling between two binaries; rpc-go internal/ packages are not designed for external import; any refactor in rpc-go risks breaking the agent build.

Rejected. The subprocess model (shelling out to rpc) is preferred — it eliminates coupling entirely.

Consequences

Positive

  • Operators gain a persistent discovery view of their AMT fleet without requiring devices to be fully activated.
  • LMS detection is captured at registration time with no new schema migration — discoveryInfo is an additive JSON column.
  • rpc-discovery has no build-time coupling to rpc-go; either binary can be updated independently.
  • The kardianos/service harness means a single Go codebase supports both Windows SCM and Linux systemd.

Negative / Risks

  • Two binaries (rpc + rpc-discovery) must be co-deployed and kept in sync on every managed device.
  • The JSON output contract of rpc amtinfo --json becomes a soft API between the two binaries — breaking output changes in rpc-go will silently break rpc-discovery parsing.
  • discoveryInfo partial writes at registration add a new write code path to Console's device registration handler that must be maintained separately from the full discovery scan write path.
  • The scoped JWT in agent-config.yaml is a long-lived credential stored on the device; Console must implement per-device token revocation to support decommissioning.

References

Clone this wiki locally