d32d9fb44b
Phase 2 (Monitoring & Health): - Central job scheduler replacing ad-hoc goroutines (internal/scheduler) - CPU usage collector via /proc/stat background sampling (internal/system/cpu_linux.go) - Temperature reading from /sys/class/thermal + /host/sys (Docker mount) - Load average from /proc/loadavg - Healthchecks.io-compatible HTTP pinger (internal/monitor/pinger.go) - System health checks: disk, memory, CPU, temp, Docker, protected containers (internal/monitor/healthcheck.go) Phase 3 (Backups): - Database auto-discovery via docker ps + docker inspect (internal/backup/dbdump.go) - Database dumping via docker exec (pg_dump / mariadb-dump) with atomic writes - Restic backup integration with auto-password generation (internal/backup/restic.go) - Backup orchestrator: DB dumps + restic snapshots + weekly prune (internal/backup/backup.go) - Manual backup trigger via dashboard button and POST /api/backup/run Dashboard UI: - CPU usage bar with load average display - Temperature with colored indicator dot - Backup status card with last run time, DB count, repo stats - "Mentés most" button for manual backup trigger Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
149 lines
3.5 KiB
Go
149 lines
3.5 KiB
Go
package web
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-controller/internal/stacks"
|
|
)
|
|
|
|
// templateFuncMap returns the FuncMap used by all HTML templates.
|
|
func (s *Server) templateFuncMap() template.FuncMap {
|
|
return template.FuncMap{
|
|
"stateColor": func(state stacks.ContainerState) string {
|
|
switch state {
|
|
case stacks.StateRunning:
|
|
return "green"
|
|
case stacks.StateStarting:
|
|
return "orange"
|
|
case stacks.StateUnhealthy:
|
|
return "yellow"
|
|
case stacks.StateStopped, stacks.StateExited:
|
|
return "red"
|
|
case stacks.StateRestarting:
|
|
return "yellow"
|
|
default:
|
|
return "gray"
|
|
}
|
|
},
|
|
"stateLabel": func(state stacks.ContainerState) string {
|
|
switch state {
|
|
case stacks.StateRunning:
|
|
return "Fut"
|
|
case stacks.StateStarting:
|
|
return "Indulás..."
|
|
case stacks.StateUnhealthy:
|
|
return "Nem egészséges"
|
|
case stacks.StateStopped, stacks.StateExited:
|
|
return "Leállítva"
|
|
case stacks.StateRestarting:
|
|
return "Újraindítás..."
|
|
case stacks.StateNotDeployed:
|
|
return "Nincs telepítve"
|
|
case stacks.StatePaused:
|
|
return "Szüneteltetve"
|
|
default:
|
|
return "Ismeretlen"
|
|
}
|
|
},
|
|
"stateIcon": func(state stacks.ContainerState) string {
|
|
switch state {
|
|
case stacks.StateRunning:
|
|
return "●"
|
|
case stacks.StateStarting:
|
|
return "◐"
|
|
case stacks.StateUnhealthy:
|
|
return "◑"
|
|
case stacks.StateStopped, stacks.StateExited:
|
|
return "○"
|
|
case stacks.StateRestarting:
|
|
return "◐"
|
|
default:
|
|
return "◌"
|
|
}
|
|
},
|
|
"stateStr": func(state stacks.ContainerState) string {
|
|
return string(state)
|
|
},
|
|
// isOperational returns true for any state where the stack has containers
|
|
// and is not stopped/exited — used by templates for showing action buttons
|
|
"isOperational": func(state stacks.ContainerState) bool {
|
|
switch state {
|
|
case stacks.StateRunning, stacks.StateStarting, stacks.StateUnhealthy, stacks.StateRestarting:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
},
|
|
"logoURL": func(slug string) string {
|
|
return s.cfg.AppLogoURL(slug)
|
|
},
|
|
"logoPNGURL": func(slug string) string {
|
|
return s.cfg.AppLogoPNGURL(slug)
|
|
},
|
|
"appPageURL": func(slug string) string {
|
|
return s.cfg.AppPageURL(slug)
|
|
},
|
|
"usageColor": func(percent float64) string {
|
|
if percent >= 85 {
|
|
return "red"
|
|
}
|
|
if percent >= 70 {
|
|
return "yellow"
|
|
}
|
|
return "green"
|
|
},
|
|
"fmtMB": func(mb uint64) string {
|
|
if mb >= 1024 {
|
|
gb := float64(mb) / 1024.0
|
|
if gb >= 10 {
|
|
return fmt.Sprintf("%.0f GB", gb)
|
|
}
|
|
return fmt.Sprintf("%.1f GB", gb)
|
|
}
|
|
return fmt.Sprintf("%d MB", mb)
|
|
},
|
|
"fmtGB": func(gb float64) string {
|
|
if gb >= 100 {
|
|
return fmt.Sprintf("%.0f GB", gb)
|
|
}
|
|
if gb >= 10 {
|
|
return fmt.Sprintf("%.1f GB", gb)
|
|
}
|
|
return fmt.Sprintf("%.2f GB", gb)
|
|
},
|
|
"subtract": func(a, b int) int {
|
|
r := a - b
|
|
if r < 0 {
|
|
return 0
|
|
}
|
|
return r
|
|
},
|
|
"screenshotURL": func(slug string, index int) string {
|
|
return s.cfg.AppScreenshotURL(slug, index)
|
|
},
|
|
"seq": func(n int) []int {
|
|
result := make([]int, n)
|
|
for i := range result {
|
|
result[i] = i + 1
|
|
}
|
|
return result
|
|
},
|
|
"tempColor": func(celsius float64) string {
|
|
if celsius > 75 {
|
|
return "red"
|
|
}
|
|
if celsius >= 60 {
|
|
return "yellow"
|
|
}
|
|
return "green"
|
|
},
|
|
"fmtTemp": func(celsius float64) string {
|
|
return fmt.Sprintf("%.0f°C", celsius)
|
|
},
|
|
"fmtLoad": func(load float64) string {
|
|
return fmt.Sprintf("%.2f", load)
|
|
},
|
|
}
|
|
}
|