---
module: agent.hw-inventory
title: Hardware Inventory — ATM hardware/OS inventory sync + CDN bandwidth probe
tab: Internal
order: 20
audience: dev
---

> **Internal · ops/support view.** Confirmed against `hiveops-module-hw-inventory` source 2026-07-01.

## What it does (and doesn't)

`hiveops-module-hw-inventory` (module name `hw-inventory`, entry class `HardwareInventoryModule`) is a **periodic push module**, not an event/incident monitor. Once per run it takes a full snapshot of the ATM's hardware and OS and **POSTs it to the platform** at `/api/atms/hardware/sync` (via `IncidentEventClient.syncHardware`). It does **not** tail journals, does **not** emit `IAT_*`/journal-incident events, and does **not** poll for fleet tasks. It is fire-and-forget inventory reporting.

It runs the collection **once on startup** and then **re-syncs on a fixed interval** (default every 24h).

What each sync collects:

| Area | Both platforms | Windows-only extras |
|---|---|---|
| CPU | model name, cores, max clock (MHz) | — |
| System board | manufacturer, model, type | — |
| Physical disks | model, serial, size, media type (SSD/HDD) | — |
| Logical drives | mount/letter, filesystem, total/free bytes | — |
| NICs | name, MAC, link speed, **measured RX/TX throughput** (sampled over 5s) | — |
| BIOS / boot | BIOS/product serial, last boot time | OS install date |
| OS | OS version string | installed patches (KB IDs + dates), installed programs, USB-lock status, Windows screen-lock status |
| CDN | effective CDN download speed (bytes/s) — see below | — |

**CDN bandwidth probe.** On every sync the module also measures how fast this ATM can pull from the CDN: it fetches the agent manifest (`latest.json`), resolves the platform patch file URL, issues a **512 KB HTTP Range request**, times it, multiplies the raw rate by a configurable cap, and ships the result as `cdnDownloadSpeedBps` on the same payload. The platform uses this so hotfix/software delivery can be paced per-device to the ATM's real link speed. A failed probe just sends `0` — the inventory sync still succeeds.

## Config properties it registers

| Key | Default | Meaning |
|---|---|---|
| `hw.inventory.enabled` | `true` | Master on/off. `false` → module logs "disabled" and stays inactive. |
| `hw.inventory.sync.interval.hours` | `24` | Hours between re-syncs (also the fixed-rate schedule period). |

Properties it **reuses** (does not own):

| Key | Used for |
|---|---|
| `agent.endpoint` | Preferred HTTP base URL (agent-proxy). If set, module uses the `agent` client prefix. |
| `incident.endpoint` | Fallback base URL if `agent.endpoint` is absent (older ATMs). If neither is set, the module goes inactive. |
| `incident.institution.key` | Institution key; sent as `X-Institution-Key` header on the CDN probe and included in the inventory payload. |
| `agent.update.check.url` | CDN manifest URL for the probe. Default `https://cdn.bcos.cloud/downloads/agent/latest.json`. |
| `task.hotfix.network.cap` | Multiplier applied to the measured raw CDN speed (default `0.9`, clamped to `0.01`–`1.0`). Same knob the hotfix delivery path uses. |
| `agent.*` / `incident.*` HTTP settings | Auth token, host header, timeouts — loaded via `HttpClientHelper.loadSettingsFromProperties(props, prefix)` under whichever prefix (`agent` or `incident`) is active. |

## Enabled / deployed to ATMs

- **Enable condition:** on by default. It self-activates whenever `hw.inventory.enabled` is not `false` **and** an `agent.endpoint` or `incident.endpoint` is configured. To disable on a specific ATM/institution, push `hw.inventory.enabled=false` (or add `hw-inventory` to `modules.disabled`) via a `CONFIG_UPDATE` fleet task.
- **Shipped how:** it is a drop-in JAR (`modules/hiveops-module-hw-inventory.jar`), discovered via ServiceLoader — **not** baked into the fat JAR. `deployment/build-dist.sh` includes it in **both** module sets: the default `atm` set and the `srv` (server-monitoring) set. So every standard install/patch ZIP carries it.
- **Retrofitting an ATM that doesn't have it yet:** deliver via a fleet `INSTALL_MODULE` task (drops the JAR into `modules/` and restarts the agent), or via a full agent update that includes the current module set.

## Common failure modes / what to check

| Symptom | Likely cause | What to check |
|---|---|---|
| No hardware ever appears for an ATM | Module inactive — no endpoint configured, or `hw.inventory.enabled=false`, or JAR missing | Confirm `agent.endpoint`/`incident.endpoint` is set; grep the module log for `hw-inventory initialized`; confirm `modules/hiveops-module-hw-inventory.jar` is present |
| Sync logs `Failed to sync hardware inventory: HTTP <code>` | agent-proxy/incident rejected the POST (auth, routing, or `/api/atms/hardware/sync` not reachable) | Verify the endpoint resolves through agent-proxy and the agent's auth token/institution key are valid |
| Windows fields (patches, programs, lock status) are empty but Linux-style fields present | Wrong collector, or PowerShell failing | These come from PowerShell (`Get-CimInstance`, `Get-HotFix`, registry reads); check the module log for `PowerShell exited <n>` warnings |
| CPU/disk/NIC fields blank | A single collector step failed but sync still ran | Each collector step is independently try/caught and logs `failed to collect <x>`; a partial payload is still sent |
| `cdnDownloadSpeedBps` is 0 | CDN probe failed or manifest had no patch URL | Non-fatal; check log for `CDN probe returned HTTP <n>` / `CDN probe failed`; verify the ATM can reach `cdn.bcos.cloud` and the manifest has `patches.windows`/`patches.linux` |
| Inventory looks ~24h stale | That's the default resync cadence | Lower `hw.inventory.sync.interval.hours` via `CONFIG_UPDATE`, or restart the agent to force an immediate sync |
| Each NIC sync adds ~5s of latency | Expected — throughput is measured by sampling `/proc/net/dev` (Linux) / `Get-NetAdapterStatistics` (Windows) twice, 5s apart | Not a bug; it's the RX/TX measurement window |
