feat: système de rebuild Docker pour installation de modules has_backend

- internal/docker/client.go : client HTTP brut sur socket Unix
  - BuildImage() : build depuis repo git avec ARG MODULES
  - RebuildAndRestart() : rebuild async + remplacement de container
  - HandleReplacement() : le container successeur arrête et renomme l'ancien
  - Restart() : redémarrage simple (enable/disable sans rebuild)
- cmd/gen-modules/main.go : générateur de registered_modules.go
  Lit MODULES env var, génère imports + appels RegisterModules()
- registered_modules.go : version par défaut (aucun module)
- main.go : appel RegisterModules(loader) + HandleReplacement() au démarrage
- settings.go : inject DockerClient, has_backend dans moduleResp/moduleJSON,
  trigger rebuild à l'install, restart à l'enable/disable
- migrations/006 : colonne has_backend sur table modules
- Dockerfile : ARG MODULES, git clone modules, go run ./cmd/gen-modules
- docker-compose.yml : socket Docker, group_add, env vars CONTAINER_NAME/GIT_REPO/GIT_BRANCH

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
enzo 2026-03-22 16:54:21 +01:00
parent dcf3b937fa
commit a61f805cd0
8 changed files with 658 additions and 27 deletions

View file

@ -0,0 +1,104 @@
// cmd/gen-modules génère registered_modules.go à partir de la variable d'env MODULES.
// Appelé pendant le build Docker : go run ./cmd/gen-modules
// MODULES = liste d'IDs séparés par des virgules (ex: "viewLogs,viewServices")
// Le fichier généré déclare RegisterModules(*modules.Loader) qui enregistre chaque module.
package main
import (
"fmt"
"os"
"strings"
"text/template"
)
const outputFile = "registered_modules.go"
// moduleDef décrit un module à importer.
type moduleDef struct {
ID string // ex: "viewLogs"
Alias string // ex: "viewlogs" (alias Go valide)
Pkg string // ex: "git.geronzi.fr/proxmoxPanel/viewLogs"
}
// tplNoModules : fichier généré quand aucun module n'est installé.
const tplNoModules = `// Code généré automatiquement par cmd/gen-modules — ne pas modifier manuellement.
// Régénéré lors du build Docker avec la liste des modules compilés.
package main
import "git.geronzi.fr/proxmoxPanel/core/backend/modules"
// RegisterModules enregistre les modules compilés dans le binaire.
func RegisterModules(l *modules.Loader) {}
`
// tplWithModules : fichier généré avec des modules.
const tplWithModules = `// Code généré automatiquement par cmd/gen-modules — ne pas modifier manuellement.
// Régénéré lors du build Docker avec la liste des modules compilés.
package main
import (
"git.geronzi.fr/proxmoxPanel/core/backend/modules"
{{- range .}}
{{.Alias}} "{{.Pkg}}"
{{- end}}
)
// RegisterModules enregistre les modules compilés dans le binaire.
func RegisterModules(l *modules.Loader) {
{{- range .}}
l.RegisterModule({{.Alias}}.New())
{{- end}}
}
`
func main() {
modulesEnv := strings.TrimSpace(os.Getenv("MODULES"))
// Pas de modules : générer la version vide
if modulesEnv == "" {
if err := os.WriteFile(outputFile, []byte(tplNoModules), 0644); err != nil {
fmt.Fprintf(os.Stderr, "Erreur écriture %s : %v\n", outputFile, err)
os.Exit(1)
}
fmt.Printf("Généré %s (aucun module)\n", outputFile)
return
}
// Parser la liste des modules
ids := strings.Split(modulesEnv, ",")
defs := make([]moduleDef, 0, len(ids))
for _, id := range ids {
id = strings.TrimSpace(id)
if id == "" {
continue
}
// Alias Go = ID en minuscules sans tirets ni underscores
alias := strings.ToLower(strings.NewReplacer("-", "", "_", "").Replace(id))
defs = append(defs, moduleDef{
ID: id,
Alias: alias,
Pkg: "git.geronzi.fr/proxmoxPanel/" + id,
})
}
// Générer le fichier avec les imports et les appels RegisterModule
tmpl, err := template.New("modules").Parse(tplWithModules)
if err != nil {
fmt.Fprintf(os.Stderr, "Erreur template : %v\n", err)
os.Exit(1)
}
f, err := os.Create(outputFile)
if err != nil {
fmt.Fprintf(os.Stderr, "Erreur création %s : %v\n", outputFile, err)
os.Exit(1)
}
defer f.Close()
if err := tmpl.Execute(f, defs); err != nil {
fmt.Fprintf(os.Stderr, "Erreur génération : %v\n", err)
os.Exit(1)
}
fmt.Printf("Généré %s avec %d module(s) : %s\n", outputFile, len(defs), modulesEnv)
}