Files
SentinelMesh/doc_brainstorming/deep-research-report(4).md
T
2026-05-19 06:39:32 +02:00

126 lines
22 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.
# Dossier technique pour le deuxième widget Glance de monitoring dagents Rust
## Conclusion opérationnelle
Oui, ton deuxième widget est **réalisable**, et il est même cohérent avec larchitecture de Glance à condition de le traiter comme **une application externe intégrée dans Glance**, pas comme un widget natif compilé “dans” Glance en Rust. Le dépôt principal de Glance est un projet **Go** avec un `go.mod`, et sa mécanique de widgets personnalisés repose aujourdhui sur quatre portes dentrée documentées par le projet lui-même : `iframe`, `html`, `extension` et `custom-api`. Glance précise aussi que les pages **ne se mettent pas à jour automatiquement en arrière-plan** et quun rechargement de page est normalement nécessaire pour récupérer les nouvelles données. Pour ton besoin — tuiles live, popup latéral, auto-découverte, installation dagent, mise à jour, métriques à fréquences différentes et états de veille/arrêt/actif — loption la plus robuste est donc : **backend Rust + petite UI web servie par ce backend + intégration dans Glance via `iframe`**. citeturn36view0turn33view1turn35view0turn34view0
Il y a aussi une nuance importante de vocabulaire : le projet étudié ici est **Glance**, pas **Glances**. La documentation de Glance dit dailleurs explicitement que le widget `server-stats` est encore “under development”, quil peut sappuyer sur le **Glance Agent** pour des serveurs distants, et que le support dautres providers “such as Glances” viendra plus tard. Autrement dit, ton besoin avancé dépasse clairement ce que le widget natif `server-stats` couvre aujourdhui. citeturn3view0
Mon verdict est donc simple : **oui pour Rust**, mais **en service externe** consommé par Glance, pas comme module interne du binaire Go de Glance. Si tu veux un rendu vraiment vivant et administrable, je te recommande de bâtir un petit produit séparé, par exemple `fleet-collector` et `fleet-agent`, puis de lafficher dans une page Glance dédiée. Cette approche servira dailleurs très bien ton **premier widget IP réseau** et ton **deuxième widget agents** avec un même modèle dinventaire. citeturn33view1turn34view0turn31view0turn35view0
## Ce que Glance permet réellement pour ce besoin
Glance organise linterface autour de **pages** et de **colonnes**. Une page peut jouer le rôle de “tab” au sens fonctionnel, avec un layout `wide` et des colonnes `full` ou `small`. Si tu veux réserver un onglet complet à ton monitoring, Glance le permet nativement côté configuration, sans toucher au code source du projet. citeturn3view0
Pour ton cas, les trois mécanismes utiles sont les suivants. Dabord, `custom-api` sait appeler une API JSON avec `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, gérer des headers, un body, des `subrequests`, puis rendre le résultat avec un template basé sur **Go `html/template`** et `gjson`. Cest puissant pour des widgets “server-rendered” relativement riches, mais la doc de Glance dit aussi explicitement que ce mode demande des notions de programmation, HTML, CSS et templates Go. Ensuite, `extension` est un protocole HTTP simple où un service externe renvoie du HTML et quelques headers spécifiques ; Glance documente néanmoins que cette API est **work in progress**, que le cache par défaut dune extension est de **30 minutes**, quil est configurable, et que le seul type de contenu supporté actuellement est `html`. Enfin, `iframe` embarque simplement une application externe à partir dune URL et dune hauteur donnée. Pour un écran de supervision avec popups, tuiles dynamiques, tri intelligent, interaction fine et mises à jour live, `iframe` est de loin la meilleure option. citeturn35view0turn31view0turn34view0turn33view1
La principale raison est le modèle dactualisation de Glance. Le README officiel dit que les widgets ne font **pas de requêtes périodiques en arrière-plan** et que les données sont récupérées au chargement puis mises en cache ; il faut normalement recharger la page pour voir les changements. Il existe bien une pull request ouverte ajoutant des “live-events” avec **polling serveur toutes les 15 secondes** et SSE pour `monitor` et `custom-api`, mais elle est **encore ouverte** au 19 mai 2026 et nappartient donc pas au comportement stable documenté du `main` actuel. Ton besoin de CPU/RAM à 1 seconde ne doit pas dépendre dune PR non mergée. citeturn33view1turn33view0
Glance reste toutefois très bon comme **conteneur**, car tu peux lui faire servir des assets via `assets-path`, injecter du HTML dans le `<head>` avec `document.head`, ajouter un `custom-css-file`, et cibler les widgets par `widget-type-*` ou `css-class`. Autrement dit, même si le vrai widget vit dans un service Rust séparé, tu peux le “fondre” visuellement dans lunivers Glance. citeturn32view0turn32view1turn32view2turn32view3
Un squelette de configuration Glance pour ce deuxième widget ressemblerait à ceci :
```yaml
pages:
- name: Infrastructure
width: wide
columns:
- size: full
widgets:
- type: iframe
title: Fleet Monitor
source: https://dash.example.net/widgets/agents
height: 820
css-class: fleet-monitor
```
Si tu veux garder un mode “dégradé” purement Glance, tu peux aussi fournir un **petit widget `custom-api`** qui naffiche quun résumé global : nombre dagents, nombre offline, charge CPU moyenne, machines en alerte, lien dinstallation et lien “ouvrir la vue détaillée”. Mais la vue principale riche doit rester dans l`iframe`. citeturn35view0turn34view0turn32view3
## Architecture recommandée pour le widget agents
Je te recommande une architecture en trois briques. **Première brique** : un `fleet-agent` Rust installé sur chaque VM ou machine physique. **Deuxième brique** : un `fleet-collector` Rust central qui reçoit les enregistrements, stocke linventaire, expose une API et un flux temps réel. **Troisième brique** : une UI web légère, servie par le collector, affichée dans Glance via `iframe`. Cette séparation colle au modèle de Glance, contourne proprement labsence dauto-refresh généralisé, et te laisse toute latitude pour le placement intelligent des tuiles, les popups, les liens personnalisés et les workflows dinstallation/mise à jour. citeturn33view1turn34view0turn35view0turn31view0
```text
[ VM / Bare metal ]
└─ fleet-agent (Rust)
├─ collecte CPU / RAM / disque / process
├─ inventaire matériel
├─ écoute veille / reboot / shutdown
└─ push JSON vers collector
[ Serveur central ]
└─ fleet-collector (Rust)
├─ API denregistrement des agents
├─ stockage inventaire + séries courtes
├─ stream SSE / WebSocket pour lUI
├─ génération commandes install / update
└─ UI web du widget
[ Glance ]
└─ page "Infrastructure"
└─ widget iframe -> UI du collector
```
Je te conseille un modèle **push** depuis les agents vers le collector, parce que ton cahier des charges inclut des événements qui se prêtent mal à un modèle purement pull : arrêt propre, passage en veille, reprise, changement d’état, heartbeat, auto-enregistrement au boot, et publication de métriques avec des fréquences hétérogènes. Comme Glance nest pas un moteur de polling continu des widgets, et comme `server-stats` est encore explicitement en développement, vouloir faire ça directement “dans Glance” te mettrait rapidement à contre-courant du produit. citeturn33view1turn3view0
La bonne granularité, à mon sens, est la suivante. **Inventaire statique** au démarrage puis deux fois par jour : hostname, OS, carte mère, modèle, vendor, serial, interfaces réseau, icône, emplacement, groupe, parent, liens. **Métriques rapides** toutes les 1 à 5 secondes : CPU, RAM, état de disponibilité, éventuellement charge GPU si la machine en a une. **Métriques lentes** toutes les 30 minutes : capacité disque, occupation des volumes, état SMART synthétique. **Événements** à la volée : démarrage, arrêt, veille, reprise, changement dIP, agent obsolète, échec dun module. Cette séparation colle bien aux capacités des APIs système disponibles et évite de transmettre trop de bruit. citeturn22view0turn24search7turn8search0turn8search4turn12search0turn11search0turn10search0turn30search6
Pour le **volet secondaire** de tes tuiles, je te conseille de ne pas tout remonter à 1 seconde. Les données de popup — SMBIOS/DMI, services, icône, emplacement, relations de parenté, liste des top processus, état détaillé des disques — peuvent être stockées côté collector et réactualisées plus lentement, voire à la demande. Les docs de `sysinfo` montrent explicitement que le CPU sappuie sur des différences temporelles, quil faut garder une même instance `System`, et quil vaut mieux utiliser des refresh ciblés pour les performances. Cette philosophie va exactement dans le sens de ton besoin “fréquences différentes selon les familles de données”. citeturn22view0turn26view0
## Stack Rust recommandée
Pour le **runtime** et lAPI réseau, la combinaison la plus naturelle est **Tokio + Axum**. Tokio est le runtime asynchrone standard de fait pour les applications réseau Rust ; sa primitive `interval` est adaptée à des boucles planifiées de collecte. Axum est conçu pour fonctionner avec Tokio et Hyper, sait gérer des APIs HTTP, les WebSockets, et fournit nativement des réponses **SSE**. Pour ton widget, SSE suffit souvent très bien : le collector pousse les changements de tuiles, et lUI met à jour la grille sans refresh. citeturn16search22turn20search2turn20search5turn16search2turn20search0turn20search4
Pour la **collecte système générale**, je recommande **`sysinfo`** comme base. La doc officielle montre que la crate couvre processus, mémoire, CPU, disques, réseaux, températures de composants, et quelle dispose de `RefreshKind`, `ProcessRefreshKind`, `DiskRefreshKind`, ainsi que dun `MINIMUM_CPU_UPDATE_INTERVAL`. Elle expose aussi des informations de carte mère, par exemple nom, vendor, version, numéro de série et asset tag via `Motherboard`. Pour les top processus, elle fournit notamment `cpu_usage()`, `memory()`, `status()`, `parent()`, `exe()` et `cmd()`. Cest une excellente base pour un agent Rust Linux-first. citeturn22view0turn25view0turn25view1turn26view0turn26view1
Pour le **matériel** et les identifiants, tu as deux étages. Dabord `sysinfo`, qui sait remonter une partie de linventaire matériel. Ensuite, pour les informations plus complètes ou plus “admin” — SMBIOS/DMI, châssis, BIOS, vendor, références — tu peux compléter avec `dmidecode` ou directement les fichiers sysfs. La doc de `dmidecode` rappelle toutefois que ces informations viennent du firmware SMBIOS/DMI et peuvent être **rapides et sûres à lire** mais **parfois peu fiables**, car elles dépendent de ce que le firmware expose. Cest important pour ton design : il faut afficher ces champs comme de linventaire déclaratif, pas comme une vérité absolue. citeturn25view0turn9search12turn9search6
Pour les **disques**, je te conseille de séparer “occupation des volumes” et “santé physique”. Loccupation se fait très bien avec `sysinfo::Disks`. La santé disque et les attributs SMART doivent venir de **`smartctl`**, car la documentation officielle indique que `smartctl` contrôle et surveille le système SMART des disques ATA/SATA, SCSI/SAS et SSD, et son code source expose un mode `--json`/`-j` pour une sortie JSON ou YAML. Cest le meilleur compromis Rust aujourdhui : exécuter `smartctl`, parser le JSON, et normaliser un petit résumé par disque pour ton popup ou tes alertes. citeturn24search7turn8search0turn8search4
Pour les **GPU**, je te recommande un design par provider optionnel. Côté NVIDIA, la référence est clairement **NVML** ; NVIDIA documente NVML comme une API C de monitoring et management des GPU, thread-safe, et base de `nvidia-smi`. En Rust, `nvml-wrapper` permet dy accéder proprement. Côté AMD, la doc ROCm indique que **AMD SMI** est linterface unifiée vers laquelle AMD pousse désormais les usages de monitoring/management GPU et quelle est la successeure de ROCm SMI. Traduction pratique : **phase 1 NVIDIA si tu veux aller vite**, **phase 2 AMD SMI si ton parc le justifie**. citeturn10search0turn10search1turn6search4turn30search1turn30search6
Pour la **base de données centrale**, tu as deux bons choix. Si ton parc reste modeste et si tu veux un déploiement très simple, **SQLite en WAL** est parfaitement défendable avec un **collector unique** et un modèle “une écriture logique à la fois”. La doc SQLite rappelle comment activer WAL et souligne que ce mode permet, en règle générale, que les écrivains ne bloquent pas les lecteurs et inversement, tout en expliquant le rôle des checkpoints. En revanche, la doc SQLite signale aussi un **bug rare WAL-reset** corrigé en **3.51.3** le 13 mars 2026, ainsi que dans certains backports. Donc si tu pars sur SQLite/WAL, veille à utiliser une version corrigée. Si tu veux monter en charge, multi-utilisateur, ou faire de la rétention longue avec analytics, **PostgreSQL** devient plus confortable. Côté Rust, **SQLx** est adapté aux deux mondes : crate async, support Tokio, support SQLite/PostgreSQL, requêtes vérifiables à la compilation. citeturn27view0turn19search0turn19search1
Pour les **mises à jour de lagent**, deux options sont sérieuses. Soit tu fais du **self-update** in-place avec une crate dédiée ; la doc de `self_update` précise quelle sait mettre à jour des exécutables Rust en place à partir de plusieurs backends de distribution. Soit, ce que je préfère dans ton contexte, tu gardes un **installeur shell** et des **binaires versionnés**, ce qui te donne un chemin dupgrade plus transparent, plus compatible avec systemd et plus facile à signer/vérifier. Pour la signature, **Minisign** est une option légère et robuste, officiellement documentée comme un outil simple de signature/vérification basé sur **Ed25519**. citeturn16search1turn17search0
## Déploiement, découverte et mises à jour
Pour la **distribution** des artefacts, Gitea est suffisant. La documentation officielle du **Generic Package Registry** explique quil peut publier des fichiers génériques comme des binaires de release, via `PUT`, et les télécharger via `GET` sur des URLs versionnées. Gitea documente aussi lauthentification API par Basic auth, query token, ou surtout `Authorization: token ...`. Concrètement, tu peux stocker dans Gitea : le binaire par plateforme, le fichier `.minisig`, un `manifest.json`, et le `install.sh`. citeturn28view0turn28view2
Dans ce modèle, ton widget central peut générer la commande dinstallation exactement dans lesprit que tu veux, par exemple :
```bash
curl -fsSL https://git.example.net/api/packages/infra/generic/fleet-agent/1.2.0/install.sh \
| bash -s -- \
--collector https://collector.example.net \
--token AGENT_REG_TOKEN \
--group vm \
--icon server \
--link https://proxmox.example.net
```
Je te conseille toutefois que ce script **ne télécharge pas directement un binaire non vérifié** : il doit récupérer le manifest, télécharger lartefact pour lOS/arch courants, vérifier la signature Minisign, installer le binaire, créer lunité systemd et démarrer le service. Cest plus sûr que le simple `curl | bash` aveugle, tout en restant simple à opérer. citeturn28view0turn17search0
Pour l**auto-découverte**, je te recommande de faire de la **self-registration** dabord, et du **mDNS/DNS-SD** seulement en option locale. Les RFC IETF disent clairement que **mDNS** fonctionne sur le **local link** en absence de DNS conventionnel, et que **DNS-SD** sert à découvrir les instances dun service à partir de son type. Cela veut dire que mDNS est pratique sur un LAN plat, mais pas un mécanisme principal pour des segments séparés, des VLANs ou des routes plus complexes. En outre, les travaux IETF sur la privacy de DNS-SD rappellent que la découverte de services divulgue typiquement des noms dhôtes et des paramètres réseau. En pratique : **annonce mDNS facultative pour le confort local**, **enregistrement explicite au collector pour le vrai fonctionnement**. citeturn14search3turn14search1turn14search7
Pour la **détection des états système**, le plus propre est de mélanger hooks systemd et écoute D-Bus. La documentation systemd indique que `ExecStop=` et `ExecStopPost=` sexécutent lors dune opération darrêt/restart du service, ce qui te donne un bon point de sortie “propre” pour publier un dernier événement. En parallèle, linterface `org.freedesktop.login1` documente les signaux `PrepareForShutdown()` et `PrepareForSleep()` envoyés juste avant et juste après extinction/suspend, avec un booléen indiquant lentrée ou la sortie de l’état. Cest exactement ce quil te faut pour les états “veille”, “arrêt”, “actif”. citeturn11search0turn12search0
Enfin, pour la **mise à jour par mini-modules**, le collector peut exposer une notion de “catalogue de modules” par agent : par exemple `smart`, `gpu-nvidia`, `gpu-amd`, `services-extra`, `netinfo-advanced`. Le widget na pas besoin dexécuter lui-même le code distant ; il peut afficher la commande exacte à lancer, ou bien lagent peut **poller un manifest signé** et proposer/appliquer lupdate localement selon une politique. Cette seconde approche est plus sûre et plus industrialisable si tu comptes dépasser quelques machines. citeturn28view0turn16search1turn17search0
## Plan de réalisation recommandé
Je te recommande un **MVP Linux-first** en trois étapes. **Étape une** : collector Rust + UI iframe + agent Rust qui remonte en push lenregistrement, le heartbeat, CPU, RAM, volumes, état de base, et un top 5 processus rafraîchi toutes les 10 à 15 secondes. Tu obtiens déjà les tuiles, l’état online/offline, les popups secondaires et la génération de commandes dinstallation. Cette première étape sappuie presque entièrement sur `tokio`, `axum`, `sysinfo`, `systemd` et la mécanique Glance `iframe`. citeturn20search2turn16search2turn22view0turn26view0turn34view0
**Étape deux** : enrichissement matériel. Tu ajoutes DMI/SMBIOS, cartes réseau, disques SMART, capteurs/temperatures disponibles, et éventuellement données GPU NVIDIA. Cette couche est surtout utile pour ton volet latéral “hardware, icon, services, lien, emplacement, parent”. Cest aussi l’étape où tu peux stabiliser ton modèle dinventaire pour quil serve **en commun** ton premier widget “cartographie IP réseau” et ton deuxième widget “agents”. citeturn25view0turn9search12turn8search0turn10search0
**Étape trois** : exploitation avancée. Tu ajoutes auto-discovery optionnelle, agent modules, politiques dupdate, AMD SMI si nécessaire, et éventuellement une petite vue Glance `custom-api` de synthèse pour les KPIs globaux. À ce stade, Glance reste le portail, mais la logique métier vit clairement dans ton service Rust, ce qui est précisément ce que larchitecture de Glance favorise déjà avec `iframe`, `extension` et `custom-api`. citeturn35view0turn31view0turn34view0
## Limites et points ouverts
La principale limite technique est que ton besoin est **beaucoup plus proche dun mini-produit de fleet monitoring** que dun simple widget statique. Ce nest pas un défaut de Glance ; cest juste que Glance documente aujourdhui un modèle de données principalement **fetch-on-load + cache**, avec des extensions HTML et des custom APIs orientées rendu, et non un framework de widgets riches temps réel comparable à une SPA supervisée par un bus d’événements. Lexistence dune PR SSE non mergée va dans ce sens : le besoin de live updates existe, mais il nest pas encore un socle stable du projet. citeturn33view1turn33view0turn31view0turn35view0
Le deuxième point ouvert est le **périmètre OS**. La stack que je te propose est excellente pour un parc **Linux / VMs / bare metal sous systemd**, parce quelle repose sur `smartctl`, login1/systemd, SMBIOS/DMI, NVML/AMD SMI et `sysinfo`. Si tu veux couvrir sérieusement Windows, BSD ou macOS avec le même niveau de détails matériels et d’événements système, il faudra des providers spécifiques ou un niveau de service un peu moins riche. `sysinfo` est multi-OS, mais tout ce qui touche au shutdown propre, à SMART, à SMBIOS détaillé et à la télémétrie GPU dépend fortement de lOS et du vendor. citeturn22view0turn9search12turn8search0turn12search0turn10search0turn30search6
Le troisième point ouvert est la **taille de parc** visée. Si tu parles de quelques dizaines de machines, SQLite en WAL avec un collector unique, un cache mémoire court et des agrégats récents est probablement suffisant. Si tu parles de centaines de nœuds, dhistoriques longs ou de multiples utilisateurs simultanés du dashboard, je partirais plus vite sur PostgreSQL et un découplage plus net entre ingestion temps réel et UI. Et si tu restes sur SQLite, je te recommande explicitement de vérifier la version déployée au regard des correctifs WAL mentionnés par la documentation SQLite de mars 2026. citeturn27view0turn19search1
En synthèse finale : **oui, tu peux ajouter ce widget avec du Rust** ; **non, je ne te recommande pas de vouloir lajouter “dans Glance” comme widget natif Rust** ; **oui, je te recommande fortement un service Rust externe affiché par `iframe` dans une page Glance**, avec un agent Rust en push, un collector temps réel, un stockage léger, une distribution via Gitea, et une vérification de signature des binaires. Cest larchitecture la plus propre, la plus maintenable, et la plus fidèle à la manière dont Glance expose aujourdhui ses points dextension. citeturn36view0turn35view0turn34view0turn31view0turn33view1