mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Modèles, discussions et fichiers disparaissaient à chaque recréation du conteneur quand /data n'était pas un volume : tout vivait dans la couche éphémère. Loki le détecte maintenant (mountinfo) et le dit — bandeau rouge dans l'UI (/api/status warn), avertissement en tête du journal, et l'entrypoint exporte LOKI_HOME pour ses sous-commandes. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
68 lines
2.6 KiB
Go
68 lines
2.6 KiB
Go
package loki
|
|
|
|
// sys_datavolume.go — garde-fou contre la PERTE DE DONNÉES en conteneur.
|
|
//
|
|
// Le symptôme vécu : modèles, discussions et fichiers disparus après un
|
|
// redémarrage du serveur. La cause, dans tous les cas observés : /data n'est
|
|
// PAS un volume monté (template Docker sans mapping, `docker run` sans -v,
|
|
// chemin hôte qui change d'un lancement à l'autre). Tout vit alors dans la
|
|
// couche d'écriture du conteneur, qui meurt avec lui à la première recréation
|
|
// (mise à jour d'image, compose down/up, redémarrage de l'array Unraid).
|
|
//
|
|
// Loki ne peut pas monter le volume à la place de l'utilisateur, mais il peut
|
|
// le VOIR et le DIRE : au démarrage en conteneur, si LOKI_HOME n'est pas un
|
|
// point de montage, on le journalise en rouge et l'UI l'affiche en bandeau.
|
|
|
|
import (
|
|
"bufio"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
// dataDirIsMounted dit si LokiHome() est un point de montage (bind mount ou
|
|
// volume Docker). Lecture de /proc/self/mountinfo — Linux seulement, or c'est
|
|
// le seul endroit où Loki tourne en conteneur. Hors conteneur : sans objet.
|
|
//
|
|
// Renvoie (monté, connu) : connu=false quand on n'a pas pu lire mountinfo —
|
|
// on ne crie pas au loup sur une simple erreur de lecture.
|
|
func dataDirIsMounted() (mounted, known bool) {
|
|
f, err := os.Open("/proc/self/mountinfo")
|
|
if err != nil {
|
|
return false, false
|
|
}
|
|
defer f.Close()
|
|
target := filepath.Clean(LokiHome())
|
|
sc := bufio.NewScanner(f)
|
|
for sc.Scan() {
|
|
// Format mountinfo : champs séparés par des espaces, le 5ᵉ (index 4)
|
|
// est le point de montage. Les espaces dans les chemins sont encodés
|
|
// \040 — décodés avant comparaison.
|
|
fields := strings.Fields(sc.Text())
|
|
if len(fields) < 5 {
|
|
continue
|
|
}
|
|
mp := strings.ReplaceAll(fields[4], `\040`, " ")
|
|
if filepath.Clean(mp) == target {
|
|
return true, true
|
|
}
|
|
}
|
|
return false, sc.Err() == nil
|
|
}
|
|
|
|
// dataVolumeWarning renvoie le message d'alerte si les données sont en périple
|
|
// ("" si tout va bien). Évalué au démarrage du serveur web et servi par
|
|
// /api/status pour le bandeau de l'UI.
|
|
func dataVolumeWarning() string {
|
|
if os.Getenv("LOKI_CONTAINER") == "" {
|
|
return "" // hors conteneur : l'utilisateur gère ses chemins
|
|
}
|
|
mounted, known := dataDirIsMounted()
|
|
if !known || mounted {
|
|
return ""
|
|
}
|
|
return "⚠️ " + LokiHome() + " n'est PAS un volume monté : modèles, discussions et fichiers seront PERDUS à la recréation du conteneur (mise à jour, redémarrage du serveur). " +
|
|
"Ajoute un mapping de volume — compose : « - /mnt/user/appdata/loki/data:/data » (et « …/models:/models ») ; " +
|
|
"docker run : « -v /chemin/hote/data:/data ». Voir docker-compose.unraid.yml du dépôt."
|
|
}
|