vm defaults: host-aware sizing + spec line on spawn + doctor check
Replaces the static model.Default* constants that drove --vcpu / --memory / --disk-size with a three-layer resolver: 1. [vm_defaults] in ~/.config/banger/config.toml (if set) 2. host-derived heuristics (cpus/4 capped at 4; ram/8 capped at 8 GiB) 3. baked-in constants (floor) Visibility: - Every `vm run` / `vm create` prints a `spec:` line before progress begins: `spec: 4 vcpu · 8192 MiB · 8G disk`. Matches the VM that actually gets created because the CLI is now the single source of truth — it resolves, populates the flag defaults, and forwards the explicit values to the daemon. - `banger doctor` adds a "vm defaults" check showing per-field provenance (config|auto|builtin) and the config file path for overrides. - `--help` shows the resolved defaults (e.g. `--vcpu int (default 4)` on an 8-core host). No `banger config init` command, no first-run side effects, no writes to the user's filesystem behind their back. Users who want explicit control set the keys; everyone else gets sensible numbers that track their hardware.
This commit is contained in:
parent
78ff482bfa
commit
21b74639d8
10 changed files with 594 additions and 56 deletions
|
|
@ -205,3 +205,65 @@ func TestLoadRejectsInvalidFileSyncEntries(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadAcceptsVMDefaults(t *testing.T) {
|
||||
configDir := t.TempDir()
|
||||
data := []byte(`
|
||||
[vm_defaults]
|
||||
vcpu = 4
|
||||
memory_mib = 4096
|
||||
disk_size = "16G"
|
||||
system_overlay_size = "12G"
|
||||
`)
|
||||
if err := os.WriteFile(filepath.Join(configDir, "config.toml"), data, 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cfg, err := Load(paths.Layout{ConfigDir: configDir})
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if cfg.VMDefaults.VCPUCount != 4 {
|
||||
t.Errorf("VCPUCount = %d, want 4", cfg.VMDefaults.VCPUCount)
|
||||
}
|
||||
if cfg.VMDefaults.MemoryMiB != 4096 {
|
||||
t.Errorf("MemoryMiB = %d, want 4096", cfg.VMDefaults.MemoryMiB)
|
||||
}
|
||||
if cfg.VMDefaults.WorkDiskSizeBytes != 16*1024*1024*1024 {
|
||||
t.Errorf("WorkDiskSizeBytes = %d, want 16 GiB", cfg.VMDefaults.WorkDiskSizeBytes)
|
||||
}
|
||||
if cfg.VMDefaults.SystemOverlaySizeByte != 12*1024*1024*1024 {
|
||||
t.Errorf("SystemOverlaySizeByte = %d, want 12 GiB", cfg.VMDefaults.SystemOverlaySizeByte)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadEmptyVMDefaultsLeavesZeros(t *testing.T) {
|
||||
// No [vm_defaults] block → cfg.VMDefaults is the zero value,
|
||||
// which the resolver will map to auto or builtin.
|
||||
cfg, err := Load(paths.Layout{ConfigDir: t.TempDir()})
|
||||
if err != nil {
|
||||
t.Fatalf("Load: %v", err)
|
||||
}
|
||||
if cfg.VMDefaults.VCPUCount != 0 || cfg.VMDefaults.MemoryMiB != 0 {
|
||||
t.Errorf("VMDefaults = %+v, want zeroed", cfg.VMDefaults)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadRejectsNegativeVMDefaults(t *testing.T) {
|
||||
cases := map[string]string{
|
||||
"vcpu": `[vm_defaults]` + "\n" + `vcpu = -1`,
|
||||
"memory": `[vm_defaults]` + "\n" + `memory_mib = -1`,
|
||||
"disk_size": `[vm_defaults]` + "\n" + `disk_size = "banana"`,
|
||||
"overlay": `[vm_defaults]` + "\n" + `system_overlay_size = "banana"`,
|
||||
}
|
||||
for name, body := range cases {
|
||||
t.Run(name, func(t *testing.T) {
|
||||
configDir := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(configDir, "config.toml"), []byte(body+"\n"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := Load(paths.Layout{ConfigDir: configDir}); err == nil {
|
||||
t.Fatal("expected error")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue