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 ./...
This commit is contained in:
parent
30f0c0b54a
commit
2362d0ae39
24 changed files with 3308 additions and 52 deletions
63
internal/daemon/dashboard.go
Normal file
63
internal/daemon/dashboard.go
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue