fix(agent): v0.3.10 cleanup orphan instance dirs on startup
- Add cleanupOrphanInstanceDirs() to remove leftover instance directories after failed deletes (common on Windows when compose.log is locked) - Log RemoveAll errors in dockerComposeRm for better visibility - Bump version to 0.3.10 and rebuild binaries
This commit is contained in:
+11
-10
@@ -426,11 +426,11 @@ L’agent est servi par Caddy depuis le dossier `agent/` monté dans le conteneu
|
||||
|
||||
### Binaires disponibles
|
||||
|
||||
- **Windows (archive complète)** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.9-windows.zip`
|
||||
- **Windows (archive complète)** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.10-windows.zip`
|
||||
- Contient `studioE5-agent.exe` + `tailscale-bin/windows/` (`tailscale.exe`, `tailscaled.exe`, `wintun.dll`) + `README-Windows.txt`.
|
||||
- **Windows (exécutable seul)** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.9.exe`
|
||||
- **Windows (exécutable seul)** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.10.exe`
|
||||
- Nécessite d’avoir installé Tailscale Windows séparément ou d’avoir les binaires dans `tailscale-bin/windows/`.
|
||||
- **Linux** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.9`
|
||||
- **Linux** : `https://studioe5.edudeploy.com/studioE5-agent-v0.3.10`
|
||||
|
||||
### Builder / préparer les binaires
|
||||
|
||||
@@ -444,13 +444,13 @@ cd /opt/studioe5-client-a/agent
|
||||
./build.sh
|
||||
```
|
||||
|
||||
Le `build.sh` génère automatiquement `studioE5-agent-v0.3.9-windows.zip` et copie les binaires versionnés dans `server/public/`.
|
||||
Le `build.sh` génère automatiquement `studioE5-agent-v0.3.10-windows.zip` et copie les binaires versionnés dans `server/public/`.
|
||||
|
||||
### Flow d’activation zéro-config (modèle commercialisable)
|
||||
|
||||
L’élève/employé n’a **aucune configuration technique** à saisir :
|
||||
|
||||
1. **Télécharger** l’agent Windows (`studioE5-agent-v0.3.9-windows.zip`).
|
||||
1. **Télécharger** l’agent Windows (`studioE5-agent-v0.3.10-windows.zip`).
|
||||
2. **Extraire** et **lancer** `studioE5-agent.exe`.
|
||||
3. **Entrer le code d’activation** à 6 caractères fourni par l’établissement (affiché dans l’UI locale `http://localhost:7070`).
|
||||
4. L’agent contacte le serveur, le serveur vérifie le code et renvoie **automatiquement** :
|
||||
@@ -778,7 +778,7 @@ Créer un package d’installation unique et professionnel par OS, incluant l’
|
||||
|
||||
### Mise à jour de l’agent vs dépendances système
|
||||
|
||||
- **L’agent peut se mettre à jour lui-même** (binaire + fichiers) depuis la v0.3.9.
|
||||
- **L’agent peut se mettre à jour lui-même** (binaire + fichiers) depuis la v0.3.10.
|
||||
- **Podman / Docker / Tailscale restent gérés par l’installateur** : l’agent vérifie leur présence et alertera l’utilisateur si une dépendance est manquante ou trop ancienne, mais ne les met pas à jour automatiquement (droits élevés, risque de casser les machines Podman, etc.).
|
||||
|
||||
---
|
||||
@@ -806,10 +806,11 @@ Créer un package d’installation unique et professionnel par OS, incluant l’
|
||||
- [x] **Nettoyer les instances/agent de test** (2026-06-27) : agent de test arrêté (`vps-8fc665eb`), `tailscaled` associé arrêté, data-dir `/tmp/studioe5-test-clienta` supprimé ; **13 instances de test supprimées de la base PostgreSQL** (`vps-8fc665eb` + `OMEGA-GAMER-60d7f87c`).
|
||||
- [x] **Nettoyer les anciens nodes/volumes Headscale de test** (2026-06-27) : nœuds `edubox`, `prof`, `invalid-*`, anciens `vps-8fc665eb`, anciens `studioe5-resolver` et `test-node-b` supprimés ; volume Docker anonyme orphelin supprimé.
|
||||
- [x] **Centralisation de la version agent** : fichier unique `agent/VERSION`, API `GET /api/agent/version`, dashboard et route `/api/download` alignés.
|
||||
- [x] **Agent v0.3.9 – synchronisation agent ↔ serveur au démarrage** : protocole `sync` / `sync_response`, suppression/lancement automatique des instances décalées pendant un offline.
|
||||
- [x] **Agent v0.3.9 – détails techniques dans l’UI locale** : version de l’agent, nodeId, version attendue par le serveur, notification de mise à jour.
|
||||
- [x] **Agent v0.3.9 – mise à jour automatique de l’agent** : détection de nouvelle version, téléchargement, remplacement du binaire via script helper et redémarrage.
|
||||
- [x] **Agent v0.3.9 – handlers asynchrones** : `start`, `stop`, `delete`, `reset` exécutés dans des goroutines pour ne plus bloquer la boucle WebSocket.
|
||||
- [x] **Agent v0.3.10 – synchronisation agent ↔ serveur au démarrage** : protocole `sync` / `sync_response`, suppression/lancement automatique des instances décalées pendant un offline.
|
||||
- [x] **Agent v0.3.10 – détails techniques dans l’UI locale** : version de l’agent, nodeId, version attendue par le serveur, notification de mise à jour.
|
||||
- [x] **Agent v0.3.10 – mise à jour automatique de l’agent** : détection de nouvelle version, téléchargement, remplacement du binaire via script helper et redémarrage.
|
||||
- [x] **Agent v0.3.10 – handlers asynchrones** : `start`, `stop`, `delete`, `reset` exécutés dans des goroutines pour ne plus bloquer la boucle WebSocket.
|
||||
- [x] **Agent v0.3.10 – nettoyage des dossiers instances orphelins au démarrage** : supprime les répertoires résiduels laissés par des `delete` incomplets (souvent `compose.log` verrouillé sous Windows).
|
||||
|
||||
### ⏳ Reste à faire
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
0.3.9
|
||||
0.3.10
|
||||
|
||||
+6
-1
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -92,7 +93,11 @@ func dockerComposeRm(dataDir, instanceID string) error {
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.RemoveAll(dir)
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
log.Printf("dockerComposeRm: failed to remove %s: %v (will retry on next startup)", dir, err)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractPublicURL tries to find the public URL from a WordPress compose config.
|
||||
|
||||
@@ -3,6 +3,7 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@@ -130,3 +131,34 @@ func getInstanceStatus(dataDir, instanceID string) string {
|
||||
}
|
||||
return "stopped"
|
||||
}
|
||||
|
||||
// cleanupOrphanInstanceDirs removes instance directories that have no entry in
|
||||
// instances.json. This typically happens on Windows when a delete operation
|
||||
// could not fully remove the directory because compose.log was locked.
|
||||
func cleanupOrphanInstanceDirs(dataDir string) {
|
||||
instancesDir := filepath.Join(dataDir, "instances")
|
||||
inst, err := loadInstances(dataDir)
|
||||
if err != nil {
|
||||
log.Printf("cleanupOrphanInstanceDirs: loadInstances error: %v", err)
|
||||
return
|
||||
}
|
||||
entries, err := os.ReadDir(instancesDir)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
log.Printf("cleanupOrphanInstanceDirs: ReadDir error: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
for _, entry := range entries {
|
||||
if !entry.IsDir() {
|
||||
continue
|
||||
}
|
||||
if _, ok := inst[entry.Name()]; !ok {
|
||||
dir := filepath.Join(instancesDir, entry.Name())
|
||||
log.Printf("cleanupOrphanInstanceDirs: removing orphan directory %s", dir)
|
||||
if err := os.RemoveAll(dir); err != nil {
|
||||
log.Printf("cleanupOrphanInstanceDirs: RemoveAll error for %s: %v", dir, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,10 @@ func main() {
|
||||
|
||||
log.Printf("[%s Agent] version=%s node=%s data-dir=%s server=%s", APP_NAME, version, cfg.NodeID, *dataDir, cfg.Server)
|
||||
|
||||
// Clean up instance directories left behind by failed deletes (common on
|
||||
// Windows when compose.log is locked during removal).
|
||||
cleanupOrphanInstanceDirs(*dataDir)
|
||||
|
||||
// Ensure Podman machine DNS is configured on Windows/macOS so images can be
|
||||
// pulled and containers can reach the internet.
|
||||
ensurePodmanMachineDNS()
|
||||
|
||||
Reference in New Issue
Block a user