v0.9.0: Storage paths registry, per-app HDD_PATH resolution, storage management UI
- Fix backup toggles not appearing (read each app's own HDD_PATH from app.yaml) - Storage paths registry in settings.json with auto-discovery from deployed apps - Settings page "Adattárolók" section with disk usage, add/remove/default/schedulable - Deploy page path field as dropdown of registered storage paths - Health check storage monitoring (mount point, disk usage alerts) - Mount-point validation utilities (Linux syscall + cross-platform stubs) - Controller docker-compose mount changed to /mnt:/mnt:rw for multi-storage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
@@ -60,6 +61,10 @@ func main() {
|
||||
logger.Fatalf("[FATAL] Failed to load settings from %s: %v", settingsPath, err)
|
||||
}
|
||||
|
||||
// --- Auto-discover storage paths from deployed apps ---
|
||||
discoveredPaths := discoverHDDPaths(cfg.Paths.StacksDir, logger)
|
||||
sett.AutoDiscoverStoragePaths(discoveredPaths, cfg.Paths.HDDPath, logger)
|
||||
|
||||
// --- Initialize stack manager ---
|
||||
stackMgr, err := stacks.NewManager(cfg, logger)
|
||||
if err != nil {
|
||||
@@ -96,7 +101,11 @@ func main() {
|
||||
|
||||
if metricsStore != nil {
|
||||
defer metricsStore.Close()
|
||||
metricsCollector := metrics.NewMetricsCollector(metricsStore, cpuCollector, cfg.Paths.HDDPath, logger)
|
||||
metricsHDDPath := cfg.Paths.HDDPath
|
||||
if paths := sett.GetStoragePaths(); len(paths) > 0 {
|
||||
metricsHDDPath = paths[0].Path
|
||||
}
|
||||
metricsCollector := metrics.NewMetricsCollector(metricsStore, cpuCollector, metricsHDDPath, logger)
|
||||
metricsCollector.Start(ctx)
|
||||
defer metricsCollector.Stop()
|
||||
logger.Println("[INFO] Metrics collector started (60s interval)")
|
||||
@@ -109,7 +118,10 @@ func main() {
|
||||
var backupMgr *backup.Manager
|
||||
if cfg.Backup.Enabled {
|
||||
backupMgr = backup.NewManager(cfg, pinger, sett, logger)
|
||||
backupMgr.SetStackProvider(&stackAdapter{mgr: stackMgr, hddPath: cfg.Paths.HDDPath})
|
||||
backupMgr.SetStackProvider(&stackAdapter{
|
||||
mgr: stackMgr,
|
||||
getStoragePaths: func() []settings.StoragePath { return sett.GetStoragePaths() },
|
||||
})
|
||||
backupMgr.AfterBackup = func() {
|
||||
nextDBDump := scheduler.NextDailyRun(cfg.Backup.DBDumpSchedule)
|
||||
nextBackup := scheduler.NextDailyRun(cfg.Backup.ResticSchedule)
|
||||
@@ -147,7 +159,7 @@ func main() {
|
||||
healthInterval = 5 * time.Minute
|
||||
}
|
||||
sched.Every("system-health", healthInterval, func(ctx context.Context) error {
|
||||
healthReport := monitor.RunHealthCheck(cfg, cpuCollector)
|
||||
healthReport := monitor.RunHealthCheck(cfg, cpuCollector, sett.GetStoragePaths())
|
||||
body := healthReport.FormatMessage()
|
||||
healthUUID := cfg.Monitoring.PingUUIDs.SystemHealth
|
||||
if healthReport.Status == "fail" {
|
||||
@@ -220,7 +232,7 @@ func main() {
|
||||
}
|
||||
pusher := report.NewPusher(&cfg.Hub, logger)
|
||||
sched.Every("hub-report", pushInterval, func(ctx context.Context) error {
|
||||
r := report.BuildReport(cfg, stackMgr, backupMgr, cpuCollector, metricsStore, Version)
|
||||
r := report.BuildReport(cfg, stackMgr, backupMgr, cpuCollector, metricsStore, Version, sett.GetStoragePaths())
|
||||
return pusher.Push(r)
|
||||
})
|
||||
logger.Printf("[INFO] Hub reporting enabled (every %s to %s)", pushInterval, cfg.Hub.URL)
|
||||
@@ -252,7 +264,7 @@ func main() {
|
||||
|
||||
// Initial alert refresh (so alerts appear immediately, not after first 5min health check)
|
||||
go func() {
|
||||
report := monitor.RunHealthCheck(cfg, cpuCollector)
|
||||
report := monitor.RunHealthCheck(cfg, cpuCollector, sett.GetStoragePaths())
|
||||
alertMgr.Refresh(report, cfg, backupMgr)
|
||||
}()
|
||||
|
||||
@@ -318,8 +330,8 @@ func setupLogger(cfg *config.Config) *log.Logger {
|
||||
|
||||
// stackAdapter implements backup.StackDataProvider using stacks.Manager.
|
||||
type stackAdapter struct {
|
||||
mgr *stacks.Manager
|
||||
hddPath string
|
||||
mgr *stacks.Manager
|
||||
getStoragePaths func() []settings.StoragePath
|
||||
}
|
||||
|
||||
func (a *stackAdapter) GetStackComposePath(name string) (string, bool) {
|
||||
@@ -351,5 +363,53 @@ func (a *stackAdapter) GetStackHDDMounts(name string) []string {
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return stacks.ParseComposeHDDMounts(s.ComposePath, a.hddPath)
|
||||
|
||||
// Priority 1: Read the app's own HDD_PATH from its app.yaml
|
||||
stackDir := filepath.Dir(s.ComposePath)
|
||||
appCfg := stacks.LoadAppConfig(stackDir)
|
||||
if appCfg != nil && appCfg.Env["HDD_PATH"] != "" {
|
||||
return stacks.ParseComposeHDDMounts(s.ComposePath, appCfg.Env["HDD_PATH"])
|
||||
}
|
||||
|
||||
// Priority 2: Try all registered storage paths (fallback)
|
||||
var allMounts []string
|
||||
seen := make(map[string]bool)
|
||||
for _, sp := range a.getStoragePaths() {
|
||||
mounts := stacks.ParseComposeHDDMounts(s.ComposePath, sp.Path)
|
||||
for _, m := range mounts {
|
||||
if !seen[m] {
|
||||
seen[m] = true
|
||||
allMounts = append(allMounts, m)
|
||||
}
|
||||
}
|
||||
}
|
||||
return allMounts
|
||||
}
|
||||
|
||||
// discoverHDDPaths scans deployed apps' app.yaml for HDD_PATH env values.
|
||||
func discoverHDDPaths(stacksDir string, logger *log.Logger) []string {
|
||||
entries, err := os.ReadDir(stacksDir)
|
||||
if err != nil {
|
||||
logger.Printf("[WARN] Cannot read stacks dir for HDD path discovery: %v", err)
|
||||
return nil
|
||||
}
|
||||
seen := make(map[string]bool)
|
||||
var paths []string
|
||||
for _, e := range entries {
|
||||
if !e.IsDir() {
|
||||
continue
|
||||
}
|
||||
appCfg := stacks.LoadAppConfig(filepath.Join(stacksDir, e.Name()))
|
||||
if appCfg == nil || !appCfg.Deployed {
|
||||
continue
|
||||
}
|
||||
if hddPath, ok := appCfg.Env["HDD_PATH"]; ok && hddPath != "" {
|
||||
cleaned := filepath.Clean(hddPath)
|
||||
if !seen[cleaned] {
|
||||
seen[cleaned] = true
|
||||
paths = append(paths, cleaned)
|
||||
}
|
||||
}
|
||||
}
|
||||
return paths
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user