Collector: ingest GE-Enforce/enrollment data with configurable pc-type mapping

Extends the computers collector so it can replace the classic api.asp
updateCompleteAsset path that the shopfloor PC fleet uses to auto-update data.

Collector schema (project naming) now accepts the GE-Enforce/enrollment shape:
machinenumber, pctype, pcsubtype, serialnumber, loggedinuser, lastboottime,
lastcheckin, ipaddress, vendorname, modelnumber, osname, installedsoftware.
- machinenumber -> Asset.assetnumber (skips the 9999 imaging placeholder, falls
  back to hostname), on create and update.
- pctype -> ComputerType via a configurable mapping (see below).
- vendor/model created if missing (free vocab); OS looked up (controlled, warns
  if unknown); pcsubtype accepted but not yet stored (warning).
- Dropped per scope: VNC/WinRM flags, warranty, DNC config, multi-NIC.

Configurable pc-type mapping (the gea-shopfloor-* imaging taxonomy ->
ComputerType): defaults + resolution live in plugins/computers/pctypemap.py
(plugin domain, contract-pure - reads Setting via shopdb.api); overrides stored
as pctypemap_<pxetype> settings, seeded on plugin install, edited in Settings >
System > "Collector PC Type Mapping" (new UI section).

Migration doc: docs/COLLECTOR-INTEGRATION.md maps classic api.asp fields +
GE-Enforce status fields to the collector schema, documents machine-number
sourcing (registry MachineNo first, then C:\Enrollment\machine-number.txt) and
that the transport is interim.

Tests: complete-asset payload maps machinenumber/pctype/vendor/model/os; 9999
placeholder falls back to hostname. 186 tests pass, naming green, app boots,
mapping UI verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
cproudlock
2026-06-26 21:35:23 -04:00
parent d20682fd06
commit 10ed83e14c
6 changed files with 332 additions and 9 deletions

View File

@@ -0,0 +1,74 @@
# Collector integration (PC auto-update)
How the shopfloor PC fleet pushes inventory into shopdb-flask, replacing the
classic ASP `api.asp?action=updateCompleteAsset` path.
## Endpoint
`POST /api/collector/computers`
Auth: API key header `X-API-Key: <key>`, resolved as `COLLECTOR_API_KEY_COMPUTERS`
then the shared `COLLECTOR_API_KEY` (ADR-006). Idempotent upsert keyed on
`hostname`.
## Payload (project naming convention: lowercase concatenated)
| Field | Meaning | Flask target |
|-------|---------|--------------|
| `hostname` (required) | identity | `Computer.hostname` |
| `machinenumber` | machine number | `Asset.assetnumber` (skips `9999` placeholder, falls back to hostname) |
| `pctype` | imaging pc-type | `Computer.computertypeid` via the configurable mapping |
| `pcsubtype` | finer class | accepted, not yet stored (warning) |
| `serialnumber` | BIOS serial | `Asset.serialnumber` |
| `loggedinuser` | current user | `Computer.loggedinuser` |
| `lastboottime` | ISO datetime | `Computer.lastboottime` |
| `lastcheckin` | ISO datetime | accepted (heartbeat) |
| `ipaddress` | primary IP | primary `Communication` |
| `vendorname` | manufacturer | `Computer.vendorid` (created if missing) |
| `modelnumber` | model | `Computer.modelnumberid` (created if missing) |
| `osname` | OS caption | `Computer.osid` (looked up; warned if unknown) |
| `installedsoftware` | `[{name, version}]` | `ComputerInstalledApp` (known apps only) |
Response: `{status, action: created|updated, assetid, identityvalue, warnings[]}`.
## Source of truth on the PC (current method, may change)
The data already exists at image time and at runtime:
- **machine number**: registry `HKLM\SOFTWARE\[WOW6432Node\]GE Aircraft Engines\Dnc\General\MachineNo`
FIRST (authoritative post Update-MachineNumber; ignore the `9999` placeholder),
then `C:\Enrollment\machine-number.txt` as fallback. This is exactly what
GE-Enforce.ps1 already does.
- **pc-type / pc-subtype**: `C:\Enrollment\pc-type.txt` / `pc-subtype.txt`
(the `gea-shopfloor-*` taxonomy).
- **serial / vendor / model / os / user / boot**: live WMI on the PC.
GE-Enforce currently writes a status JSON to the SFLD share rather than POSTing.
Whatever transport is used (a relay reading those status files, or a direct POST
later), map its field names to the table above.
## pc-type mapping (configurable)
`pctype` (e.g. `gea-shopfloor-cmm`) is mapped to a flask Computer Type through
`pctypemap_<pxetype>` settings (Settings > System > "Collector PC Type Mapping").
Defaults live in `plugins/computers/pctypemap.py` and are seeded on plugin
install; edit per site in the UI. Unmapped pc-types are recorded as a warning,
not an error.
## Classic api.asp field mapping (for migrating the PowerShell scripts)
| Classic `updateCompleteAsset` form field | Collector field |
|---|---|
| `hostname` | `hostname` |
| `machineNo` | `machinenumber` |
| `pcType` | `pctype` |
| `serialNumber` | `serialnumber` |
| `loggedInUser` | `loggedinuser` |
| `lastBootUpTime` / `lastBootTime` | `lastboottime` |
| `manufacturer` | `vendorname` |
| `model` | `modelnumber` |
| `osVersion` | `osname` |
| `installedApps` | `installedsoftware` |
Not carried over (no current home): warranty fields, DNC config, multi-NIC
detail beyond the primary IP, VNC/WinRM flags.