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

6.3 KiB
Raw Blame History

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.