Files
project.linkedcorp.net/docs/ARQUITECTURA-INVENTARIO.md
T
Milton Gonzalez 420a794c9e feat: version 4.16.0 -- Equipos: tipo de licencia y software agrupado por fabricante
Clasificador por reglas sin IA, correccion manual (migracion 040) y filas desplegables en ListView.
Flyout por encima de popups.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 12:36:02 -05:00

104 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Arquitectura de inventario — menú "Equipos"
Diseño del módulo Equipos de Project. Se trajo de `linkedtrack.linkedcorp.net` (que sigue como
producto aparte, sin cambios) y se reescribió siguiendo las reglas de Project: mismo login, roles,
auditoría, UI Fluent y una sola base `project_linkedcorp`.
## Decisión de fondo
| Opción | Veredicto |
|---|---|
| Servidor GLPI completo | Descartado: demasiada administración para solo inventariar. |
| Agente 100% propio | Descartado: reescribir el sondeo de hardware (WMI, EDID, SNMP) es frágil y caro. |
| **Agente GLPI oficial + colector propio dentro de Project** | **Elegido.** El agente recolecta; Project recibe, guarda y muestra. |
## Flujo
```
GLPI Agent (cada PC/servidor) --POST inventario--> https://project.linkedcorp.net/api/inventory
(ingest.js: token -> inflar -> parsear JSON/XML
-> normalizer.js -> upsert por deviceid
-> diff en device_changes)
Navegador (superadmin/admin/it_manager) --JWT--> /api/devices -> menú "Equipos"
```
- **Handshake:** el agente primero manda un `contact` (JSON) o `PROLOG` (XML). Se responde sin
guardar nada (`{"status":"ok","expiration":"24"}` o `<REPLY><RESPONSE>SEND</RESPONSE>…`).
- **Ingesta autenticada por token**, no por JWT: tabla `inventory_tokens` (hash sha256 para validar
y copia cifrada para recuperar el instalador). El
agente lo manda como contraseña Basic (`user`/`password` del `agent.cfg`), `Bearer`,
`X-Ingest-Token` o `?token=`. Sin token válido → `401`.
- Compatibilidad: `?token=` sigue aceptado para agentes instalados; la aplicación censura ese
parámetro en sus logs. El proxy inverso debe censurarlo también en sus propios access logs.
- **Pendiente de seguridad:** hoy un instalador puede usar el mismo token en varios equipos.
Vincular automáticamente token y `deviceid` rompería esos agentes ya instalados. Antes de
activarlo se necesita inventariar instalaciones y migrar a un token por equipo; luego añadir
la asociación y rechazar inventarios de otro `deviceid`.
- **Rutas:** `POST /api/inventory` (propia; pasa por el Custom Location `/api` de NPM sin cambios)
y alias `POST /front/inventory.php` (ruta nativa de GLPI). Se montan ANTES de `express.json`
porque usan cuerpo crudo.
- **Límites:** cuerpo máx. 15 MB (`INVENTORY_MAX_BYTES`), inflado máx. 4× (anti zip-bomb).
- Cada IP tiene límite de 120 peticiones/minuto; máximo dos ingestiones simultáneas. El token se
valida antes de leer el cuerpo y el parseo se ejecuta en un worker con límite de tiempo.
- **Upsert por `deviceid`** (estable), nunca por hostname. Componentes se reemplazan completos en
una transacción; el diff (RAM, disco agregado/retirado, software instalado/desinstalado, SO,
hostname) queda en `device_changes`.
- **Baja lógica:** `status = retired`; un reporte nuevo NO reactiva un equipo dado de baja.
- **Crudo para depurar:** último reporte por equipo en `storage/inventories/<hash>.json|xml`
(se sobrescribe; descarga `GET /api/devices/:id/raw`).
## Normalización
`backend/src/modules/devices/normalizer.js`: el JSON nativo y el XML (en mayúsculas) comparten
nombres de campo, así que el XML se pasa a minúsculas y ambos usan el mismo mapeo. Todo campo
ausente queda `null` (el formato varía por versión del agente y SO). Tipo de equipo
(`desktop/laptop/server/virtual/printer/network/other`) se infiere de `chassis_type`, `vmsystem`,
nombre del SO e `itemtype`. Lo que no tiene columna (impresoras/red SNMP, antivirus, video,
batería) se guarda en `devices.extra_json`.
## Clasificación de software
`softwareClassifier.js` asigna el tipo y el fabricante **al leer**, con reglas de nombre y fabricante
(sin IA ni consultas externas): por eso una regla nueva aplica sin esperar otro reporte. El agente no
informa si un programa es gratis o de pago ni si tiene licencia; el resultado es orientativo. Las
correcciones manuales viven en `software_classifications`. Lo que no está en las listas queda sin
clasificar: no se adivina. La pantalla agrupa por fabricante; los productos Microsoft con licencia
quedan fuera del grupo.
## Instalar el agente en un equipo
1. Superadmin/admin: menú **Equipos → Agentes → Generar token** (se muestra una sola vez).
2. En el equipo, instalar GLPI Agent (MSI en Windows; `.deb`/`.rpm`/tarball en Linux) con:
```
server = https://project.linkedcorp.net/api/inventory
user = project
password = <token>
tag = <opcional>
```
Windows (instalador): `SERVER=… USER=project PASSWORD=<token>`.
3. Forzar un envío: `glpi-agent --force` (Linux) / "Forzar inventario" en la página del agente
(`http://localhost:62354`) en Windows. El equipo aparece en **Equipos** al primer POST.
## Instalador con un clic (Windows)
Equipos → Agentes → "Instalador para Windows": genera `instalar-glpi-agent.bat` en el navegador con
`SERVER=<origen>/api/inventory`, `USER=project`, `PASSWORD=<token>` y `TAG` opcional. El .bat se
auto-eleva, descarga `GLPI-Agent-<ver>-x64.msi` de GitHub (versión fijada en
`frontend/src/pages/Equipos/agentInstaller.js#GLPI_AGENT_VERSION`; o usa el .msi que esté junto al
.bat), instala con `msiexec /qn` y `RUNNOW=1`, y verifica que el servicio `glpi-agent` corra. El
token solo se conoce al crearlo, por eso el .bat se genera en la pantalla y no en el servidor.
Antes de instalar, el .bat verifica el token (`POST` de prueba: `400` válido, `401` inválido, `000` sin
conexión) y se detiene si no es válido; después fuerza la configuración en el registro (cubre equipos que
ya tenían el agente). Proceso por cliente: generar UN token en su Project → descargar el .bat desde ahí →
ejecutarlo en cada PC.
Linux: usar el instalador oficial `glpi-agent-<ver>-linux-installer.pl --server=… --user=… --password=…`.
## Pendientes / por verificar con un agente real
- Confirmar que el agente acepta la respuesta del handshake tal cual (si no, ajustar `ingest.js`).
- Capturar un JSON real (`glpi-agent --local=/tmp/inv --json`) y contrastar campos con
`normalizer.js` (hoy basado en el formato documentado del agente).
- Impresoras/red por SNMP (`netinventory`): solo se guarda lo básico + `extra_json`; falta una
vista propia cuando haya un caso real.
- Panel de impresoras con contador de páginas/tóner y export CSV: fase 2.