banger/internal/daemon/dashboard.go
Thales Maciel 2362d0ae39
Serve a local web UI from bangerd
Add a localhost-only web console so VM and image management no longer depends on the CLI for every inspection and lifecycle action.

Wire bangerd up to a configurable web listener, expose dashboard and async image-build state through the daemon, and serve CSRF-protected HTML pages with host-path picking, VM/image detail views, logs, ports, and progress polling for long-running operations.

Keep the browser path aligned with the existing sudo and host-owned artifact model: surface sudo readiness, print the web URL in daemon status, and document the new workflow. Polish the UI with resource usage cards, clearer clickable affordances, cancel paths, confirmation prompts, image-name links, and HTTP port links.

Validation: GOCACHE=/tmp/banger-gocache go test ./...
2026-03-21 16:47:47 -03:00

63 lines
1.8 KiB
Go

package daemon
import (
"context"
"banger/internal/api"
"banger/internal/model"
"banger/internal/system"
)
func (d *Daemon) DashboardSummary(ctx context.Context) (api.DashboardSummary, error) {
summary := api.DashboardSummary{
GeneratedAt: model.Now(),
Sudo: api.SudoStatus{
Command: "sudo -v",
},
}
if err := system.CheckSudo(ctx); err != nil {
summary.Sudo.Error = err.Error()
} else {
summary.Sudo.Available = true
}
if host, err := system.ReadHostResources(); err == nil {
summary.Host.CPUCount = host.CPUCount
summary.Host.TotalMemoryBytes = host.TotalMemoryBytes
}
if usage, err := system.ReadFilesystemUsage(d.layout.StateDir); err == nil {
summary.Host.StateFilesystemTotalBytes = usage.TotalBytes
summary.Host.StateFilesystemFreeBytes = usage.FreeBytes
}
images, err := d.store.ListImages(ctx)
if err != nil {
return api.DashboardSummary{}, err
}
for _, image := range images {
summary.Banger.ImageCount++
if image.Managed {
summary.Banger.ManagedImageCount++
}
}
vms, err := d.store.ListVMs(ctx)
if err != nil {
return api.DashboardSummary{}, err
}
for _, vm := range vms {
summary.Banger.VMCount++
summary.Banger.ConfiguredVCPUCount += vm.Spec.VCPUCount
summary.Banger.ConfiguredMemoryBytes += int64(vm.Spec.MemoryMiB) * 1024 * 1024
summary.Banger.ConfiguredDiskBytes += vm.Spec.WorkDiskSizeBytes
summary.Banger.UsedSystemOverlayBytes += vm.Stats.SystemOverlayBytes
summary.Banger.UsedWorkDiskBytes += vm.Stats.WorkDiskBytes
if vm.State == model.VMStateRunning && system.ProcessRunning(vm.Runtime.PID, vm.Runtime.APISockPath) {
summary.Banger.RunningVMCount++
summary.Banger.RunningCPUPercent += vm.Stats.CPUPercent
summary.Banger.RunningRSSBytes += vm.Stats.RSSBytes
summary.Banger.RunningVSZBytes += vm.Stats.VSZBytes
}
}
return summary, nil
}