Files

304 lines
19 KiB
JSON
Raw Permalink 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.
{
"meta": {
"title": "Architettura di ProxMenux Monitor — AppImage, Flask, SQLite, WebSocket | ProxMenux",
"description": "Struttura di ProxMenux Monitor: AppImage, blueprint Flask, attività in background, dati da psutil, pvesh, smartctl e journalctl, archiviazione SQLite, terminale WebSocket, provider IA, canali di notifica, proxy inverso e Fail2Ban opzionale.",
"ogTitle": "ProxMenux Monitor Architettura",
"ogDescription": "Dentro ProxMenux Monitor: AppImage, blueprint Flask, attività in background, SQLite, WebSocket, provider IA e canali di notifica.",
"twitterTitle": "ProxMenux Monitor Architettura",
"twitterDescription": "AppImage, Flask, SQLite, WebSocket, provider IA e canali di notifica: dentro Monitor."
},
"header": {
"title": "Architettura",
"description": "Come viene distribuito ProxMenux Monitor, cosa contiene l’AppImage e come le richieste del browser passano da Flask agli strumenti dell’host e all’archivio SQLite.",
"section": "ProxMenux Monitor"
},
"intro": {
"title": "Un processo, molte responsabilità",
"body": "Un processo Python ascolta su TCP 8008. Serve la versione statica Next.js, espone l’API REST, gestisce il terminale WebSocket, esegue Health Monitor e invia notifiche. Non richiede un server web separato, un broker di messaggi o un database esterno."
},
"requestFlow": {
"heading": "Percorso di una richiesta",
"intro": "Una richiesta di dati tipica segue questo percorso; le preferenze del browser possono essere gestite localmente:",
"diagramCaption": "Le rotte protette verificano JWT con autenticazione attiva. Rotte principali e blueprint restituiscono dati in cache o appena raccolti. Il controllo Fail2Ban opzionale consulta la lista dei blocchi in cache. Le intestazioni IP inoltrate sono attendibili solo con PROXMENUX_TRUST_PROXY=1; altrimenti usa l’indirizzo della connessione. Lo stato persistente include SQLite e file JSON come auth.json.",
"diagramArrowLabel": "HTTP / WS",
"nodes": {
"clientLabel": "Cliente",
"clientDetail": "Browser o PWA\n+ proxy opzionale\nNginx / Caddy /\nTraefik",
"flaskLabel": "Flask :8008",
"flaskDetail": "Blueprint\nMiddleware JWT\nControllo Fail2Ban\n(se installato)",
"hostLabel": "Strumenti dell’host",
"hostDetail": "psutil\npvesh\nsmartctl\njournalctl",
"stateLabel": "Stato locale",
"stateDetail": "SQLite DB\n+ auth.json"
},
"threadsIntro": "Il processo esegue anche <strong>thread in background</strong>. Questi esempi raccolgono dati, aggiornano cache e SQLite e inviano notifiche. Esistono altre attività; l’invio dipende dalla relativa attivazione:",
"headerThread": "Thread",
"headerCadence": "Cadenza",
"headerJob": "Attività pianificata",
"rows": [
{
"thread": "_temperature_collector_loop",
"cadence": "60 s",
"job": "Salva temperatura CPU e campioni di latenza nel database storico, così i grafici hanno dati anche senza browser connessi."
},
{
"thread": "_health_collector_loop",
"cadence": "5 min",
"job": "Esegue il ciclo Health Monitor delle dieci categorie, salva errori e osservazioni sui dischi, gestisce gli avvisi ignorati e passa i nuovi eventi al motore di notifica."
},
{
"thread": "_vital_signs_sampler",
"cadence": "CPU 5 s; temperatura 15 s; memoria 30 s",
"job": "Campiona CPU, memoria e temperatura CPU per gli indicatori e il rilevamento di condizioni prolungate, indipendentemente dal controllo generale di cinque minuti."
},
{
"thread": "notification_manager.start()",
"cadence": "Basato su eventi",
"job": "Avvia gli osservatori di journal, attività e hook (<code>JournalWatcher</code>, <code>TaskWatcher</code>, <code>ProxmoxHookWatcher</code>) e invia ai canali configurati, con riformulazione IA opzionale."
}
]
},
"systemd": {
"heading": "Unità systemd",
"intro": "L’installer crea l’unità <code>/etc/systemd/system/proxmenux-monitor.service</code>. Configurazione predefinita:",
"items": [
"<strong><code>User=root</code></strong>: il servizio usa privilegi root per SMART, <code>pvesh</code> e gestione ZFS. I processi del terminale web ereditano questi permessi.",
"<strong><code>Restart=on-failure</code></strong> con attesa di dieci secondi: il servizio riparte automaticamente dopo un’uscita con errore.",
"<strong><code>After=network.target</code></strong>: ordina l’avvio dopo quel target; non garantisce IP assegnato, DNS o connettività esterna."
],
"inspectTitle": "Esaminare l’unità attuale"
},
"appimage": {
"heading": "Cosa contiene l’AppImage",
"intro": "L’AppImage contiene un filesystem montato all’esecuzione. <code>AppRun</code> alla radice prepara l’ambiente e avvia <code>flask_server.py</code>:",
"consequencesIntro": "Due conseguenze di questo layout:",
"consequences": [
"<strong>Pacchetti Python inclusi.</strong> I pacchetti Python sono distribuiti nell’AppImage e girano sull’interprete Python dell’host stesso, 3.11 (PVE 8) o 3.13 (PVE 9), senza installare nulla nel Python di sistema dell’host. L’app usa comunque interfacce del kernel e strumenti esterni dell’host.",
"<strong>Client hardware inclusi.</strong> Sono presenti <code>ipmitool</code>, <code>lm-sensors</code> e <code>upsc</code>. Le letture richiedono hardware compatibile, accesso ai sensori e, per l’UPS, un server NUT configurato."
]
},
"flask": {
"heading": "Struttura dell’applicazione Flask",
"intro": "<code>flask_server.py</code> crea un’istanza <code>Flask(__name__)</code> con origini CORS limitate, registra direttamente dieci blueprint e inizializza le rotte del terminale. La tabella mostra i moduli principali; sono registrati anche i blueprint di PBS, collegamenti del Monitor, audit e backup VM. I precaricamenti specifici di PVE si eseguono solo sugli host PVE.",
"headerBlueprint": "Blueprint / modulo",
"headerPrefix": "Prefisso delle rotte",
"headerOwns": "Responsabilità",
"rows": [
{
"blueprint": "flask_server.py",
"prefix": [
"/api/system",
"/api/storage",
"/api/network",
"/api/vms",
"/api/hardware",
"/api/logs",
"/api/prometheus"
],
"owns": "Endpoint principali, web statico e controllo Fail2Ban opzionale se il jail <code>proxmenux</code> è presente sull’host."
},
{
"blueprint": "flask_auth_routes.py",
"prefix": [
"/api/auth/*"
],
"owns": "Accesso, emissione JWT, configurazione e verifica TOTP, cambio password e token API."
},
{
"blueprint": "flask_health_routes.py",
"prefix": [
"/api/health/*"
],
"owns": "Controlli di stato, dettagli, errori attivi e ignorati e impostazioni di silenziamento. Le rotte protette richiedono autenticazione quando attiva."
},
{
"blueprint": "flask_terminal_routes.py",
"prefix": [
"/api/terminal/* + WS"
],
"owns": "Assegna un PTY per sessione e lo collega via WebSocket a <code>xterm.js</code> nel browser."
},
{
"blueprint": "flask_notification_routes.py",
"prefix": [
"/api/notifications/*"
],
"owns": "Creazione, lettura, modifica e rimozione dei canali; prove, IA, cronologia e invii manuali."
},
{
"blueprint": "flask_security_routes.py",
"prefix": [
"/api/security/*"
],
"owns": "Errori di accesso e, con Fail2Ban installato, stato del jail, blocchi e sblocco manuale."
},
{
"blueprint": "flask_proxmenux_routes.py",
"prefix": [
"/api/proxmenux/*"
],
"owns": "Legge le ottimizzazioni ProxMenux registrate sull’host."
},
{
"blueprint": "flask_oci_routes.py",
"prefix": [
"/api/oci/*"
],
"owns": "Funzioni di distribuzione di applicazioni OCI e container su Proxmox VE 9.1+."
}
],
"endpointsLink": "Gli endpoint di integrazione e i loro formati sono descritti in <link>Riferimento API</link>."
},
"dataSources": {
"heading": "Fonti dati",
"intro": "I dati dell’host provengono soprattutto da librerie standard, file e comandi amministrativi. Alcuni dati degli ospiti dipendono anche da QEMU Guest Agent o da comandi nel CT:",
"headerSource": "Fonte",
"headerUsedFor": "Usato per",
"rows": [
{
"source": "psutil",
"usedFor": "Carico CPU, memoria, swap, utilizzo dei montaggi, contatori di rete e processi."
},
{
"source": "pvesh / qm / pct",
"usedFor": "Informazioni del nodo Proxmox, inventario e configurazione VM/CT, storage e cronologia delle attività."
},
{
"source": "smartctl",
"usedFor": "Attributi SATA/NVMe, stato SMART, usura, vita utile, modello e numero di serie."
},
{
"source": "zpool / zfs",
"usedFor": "Stato del pool (ONLINE / DEGRADED / FAULTED / UNAVAIL), avanzamento dello scrub e utilizzo dei dataset."
},
{
"source": "journalctl",
"usedFor": "Log di sistema, processi terminati per OOM, errori ATA/NVMe/dm, sicurezza e unità di servizio personalizzate."
},
{
"source": "ip / iproute2",
"usedFor": "Interfacce, indirizzi, bridge, bond e dispositivi gestiti da OVS."
},
{
"source": "nvidia-smi · intel_gpu_top",
"usedFor": "Dati GPU disponibili su utilizzo, VRAM, temperatura e codifica/decodifica. I campi dipendono da produttore, strumento e driver."
},
{
"source": "lspci · lscpu · dmidecode",
"usedFor": "Topologia PCIe, modello e topologia CPU, scheda madre e BIOS."
},
{
"source": "ipmitool · sensors",
"usedFor": "Sensori fuori banda, ventole e temperature della scheda madre, se l’hardware li supporta."
},
{
"source": "upsc (NUT)",
"usedFor": "Stato batteria, carico e autonomia UPS con un server NUT configurato."
}
],
"cacheTitle": "Cache per ridurre le richieste all’host",
"cacheBody": "I risultati costosi di <code>smartctl -a</code> e <code>pvesh get</code> sono conservati temporaneamente nel processo Flask per ridurre le richieste a dischi e API del cluster. La durata varia: secondi per le metriche e minuti per SMART."
},
"persistence": {
"heading": "Persistenza",
"intro": "Diversi file di stato hanno contenuti e requisiti di accesso differenti:",
"headerPath": "Path",
"headerOwner": "Proprietario",
"headerContents": "Contenuto",
"rows": [
{
"path": "/usr/local/share/proxmenux/health_monitor.db",
"owner": "root:root",
"contents": "Database SQLite. Tabelle: <code>errors</code>, <code>events</code>, <code>disk_registry</code>, <code>disk_observations</code>, <code>user_settings</code>, <code>notification_history</code>, <code>excluded_storages</code>, <code>excluded_interfaces</code>. Modalità journal WAL."
},
{
"path": "/usr/local/share/proxmenux/.notification_key",
"owner": "root <code>0600</code>",
"contents": "Chiave principale di 32 byte per i segreti di notifica ENC2. Usa sale casuale per valore, chiavi derivate e MAC. I vecchi valori XOR sono supportati per la migrazione."
},
{
"path": "/root/.config/proxmenux-monitor/auth.json",
"owner": "root:root",
"contents": "Configurazione di accesso: attivazione, utente, hash password PBKDF2-HMAC-SHA256 con salt, segreto TOTP, codici di recupero, chiave JWT dell’installazione, metadati dei token API e hash di revoca. I vecchi hash SHA-256 vengono migrati all’accesso riuscito."
},
{
"path": "/var/log/proxmenux-auth.log",
"owner": "root:root",
"contents": "Log di autenticazione in testo semplice, indipendente da Fail2Ban. Se il jail <code>[proxmenux]</code> è installato e attivo, legge il file per rilevare errori di accesso ripetuti. Senza quel jail, il log resta consultabile."
}
],
"backupTitle": "Salvare auth.json prima della reinstallazione",
"backupBody": "Sostituire l’AppImage normalmente conserva <code>/root/.config/proxmenux-monitor/auth.json</code> e <code>/usr/local/share/proxmenux/health_monitor.db</code>. Conserva <code>auth.json</code> con jwt_secret per mantenere validità e metadati dei token. Il database conserva separatamente stato e notifiche. Salva <code>.notification_key</code> insieme per ripristinare i segreti dei canali; il solo database non ripristina l’autenticazione API."
},
"health": {
"heading": "Ciclo Health Monitor",
"intro": "Circa ogni cinque minuti, il processo in background invoca <code>health_monitor.py</code> per i controlli delle dieci categorie del pannello:",
"items": [
"Servizi PVE critici (<code>pveproxy</code>, <code>pvedaemon</code>, <code>pvestatd</code>, <code>pve-cluster</code>).",
"Storage Proxmox: <code>pvesh get /storage</code> e disponibilità di ciascuno.",
"Dischi e filesystem: SMART, errori I/O in dmesg, stato ZFS e capacità dei montaggi.",
"VM e CT: errori di avvio, arresti anomali, errori QMP e problemi di spegnimento.",
"Rete: stato di bridge e bond, collegamenti e latenza verso il gateway.",
"Aggiornamenti: pacchetti in attesa e patch di sicurezza.",
"Log: schemi persistenti, picchi e sequenze a cascata nel journal di sistema.",
"Memoria: interventi dell’OOM killer e pressione RAM prolungata.",
"CPU: utilizzo e temperatura della CPU rispetto alle soglie configurabili; i sensori disponibili dipendono dall’hardware.",
"Sicurezza: errori di accesso, blocchi e stato del jail Fail2Ban."
],
"afterIntro": "I risultati usano <code>error_key</code>, categoria e gravità stabili. I record esistenti in <code>errors</code> vengono aggiornati sul posto (<code>last_seen</code>, gravità, motivo), senza duplicarli. L’invio delle notifiche ha anche regole proprie di impronta e intervallo.",
"cycleEnd": "La pulizia può risolvere errori obsoleti con la <em>durata del silenziamento</em> per categoria e regole di stato, rimuovere voci orfane di risorse eliminate e cancellare <code>events</code> oltre 30 giorni. Le categorie sono in <link>Pannello → Health Monitor</link>."
},
"notifications": {
"heading": "Motore di notifica",
"intro": "<code>notification_manager.py</code> coordina l’invio: carica i canali, gestisce la coda e offre un’API Python per Flask e Health Monitor e un ingresso CLI per gli hook <code>.sh</code> di ProxMenux.",
"items": [
"Gli <strong>osservatori</strong> generano eventi: <code>JournalWatcher</code> segue il journal, <code>TaskWatcher</code> consulta le attività Proxmox, <code>ProxmoxHookWatcher</code> riceve hook di backup, replica e snapshot e <code>PollingCollector</code> gestisce fonti lente.",
"I <strong>modelli</strong> trasformano eventi in titolo e testo. Il provider IA configurato (OpenAI / Anthropic / Gemini / Groq / Ollama / OpenRouter) può riformularli in linguaggio naturale. Entrambe le versioni sono salvate in <code>notification_history</code>.",
"I <strong>canali</strong> inviano tramite servizi come Telegram, Discord, email, Gotify, Pushover e Apprise. Le implementazioni in <code>notification_channels.py</code> condividono <code>create_channel()</code> / <code>send()</code>.",
"<strong>Cifratura.</strong> Le impostazioni sensibili (<code>telegram.bot_token</code>, <code>discord.webhook_url</code>, <code>pushover.user_key</code>, <code>pushover.api_token</code>, <code>ai_api_key_*</code>, <code>email.password</code>) vengono cifrate con la chiave di <code>.notification_key</code> prima del salvataggio e mascherate nell’interfaccia."
],
"linksFooter": "Controlli per evento, opzioni dei canali e IA sono descritti in <notifLink>Impostazioni → Notifiche</notifLink> e <aiLink>Impostazioni → Assistente IA</aiLink>."
},
"websocket": {
"heading": "Terminale WebSocket",
"intro": "La scheda <em>Terminale</em> collega un client leggero <code>xterm.js</code> a un PTY del server via WebSocket. Esistono due modalità:",
"items": [
"<strong>Modalità HTTP, predefinita:</strong> il server Flask integrato con <code>flask-sock</code> gestisce il passaggio al protocollo WebSocket.",
"<strong>Modalità HTTPS / WSS:</strong> il server TLS usa <code>gevent.pywsgi.WSGIServer</code> con il suo gestore predefinito; <code>flask-sock</code> gestisce le connessioni WebSocket su TLS."
],
"outro": "I processi figli del terminale ereditano <code>User=root</code> dal servizio. Aprire un WebSocket richiede un ticket breve monouso ottenuto dall’endpoint autenticato dei ticket del terminale con permessi amministrativi.",
"proxyNote": "Con un proxy inverso, abilita WebSocket e le intestazioni <code>Upgrade</code> e <code>Connection</code>. Il terminale richiede questo inoltro."
},
"proxy": {
"heading": "Proxy inverso e Fail2Ban",
"intro": "La scelta dell’IP client e il blocco applicativo opzionale dipendono da queste impostazioni e componenti:",
"items": [
"<strong>Scelta dell’IP client.</strong> Il controllo <code>before_request</code> e il log di accesso si fidano di <code>X-Forwarded-For</code>, poi <code>X-Real-IP</code>, solo con PROXMENUX_TRUST_PROXY=1. Altrimenti usano <code>request.remote_addr</code>. Le intestazioni inoltrate non sono accettate automaticamente.",
"<strong>Fail2Ban applicativo opzionale.</strong> Una connessione proxy può mostrare l’IP del proxy come origine TCP. Con l’IP client attendibile e il jail <code>proxmenux</code> attivo, Flask rifiuta gli IP bloccati con HTTP 403. La lista resta in cache per 30 secondi e si aggiorna alle richieste dopo la scadenza, senza timer dedicato."
],
"calloutTitle": "Fail2Ban non è incluso",
"calloutBody": "Fail2Ban <strong>non</strong> è incluso né installato automaticamente. Si può installare da Sicurezza di Monitor o <link>Sicurezza → Fail2Ban</link> in ProxMenux Scripts. Senza <code>fail2ban-client</code> o il jail <code>proxmenux</code>, questo controllo non blocca richieste. Resta valida la politica di autenticazione configurata.",
"outro": "Esempi Nginx/Caddy/Traefik e guida del jail sono in <accessLink>Accesso e autenticazione</accessLink> e <fail2banLink>Sicurezza → Fail2Ban</fail2banLink>."
},
"whereNext": {
"heading": "Come proseguire",
"items": [
{
"label": "Accesso e autenticazione",
"href": "/docs/monitor/access-auth",
"tail": " — primo avvio, password e TOTP 2FA, esempi di proxy inverso e jail Fail2Ban."
},
{
"label": "Riferimento API",
"href": "/docs/monitor/api",
"tail": " — endpoint di integrazione, gestione token e convenzioni di autenticazione."
},
{
"label": "Impostazioni → ProxMenux Monitor",
"href": "/docs/settings/proxmenux-monitor",
"tail": " — controllo del servizio e verifica dello stato nel menu testuale ProxMenux."
}
]
}
}