Hard-cut banger away from source-checkout runtime bundles as an implicit source of\nimage and host defaults. Managed images now own their full boot set,\nimage build starts from an existing registered image, and daemon startup\nno longer synthesizes a default image from host paths.\n\nResolve Firecracker from PATH or firecracker_bin, make SSH keys config-owned\nwith an auto-managed XDG default, replace the external name generator and\npackage manifests with Go code, and keep the vsock helper as a companion\nbinary instead of a user-managed runtime asset.\n\nUpdate the manual scripts, web/CLI forms, config surface, and docs around\nthe new build/manual flow and explicit image registration semantics.\n\nValidation: GOCACHE=/tmp/banger-gocache go test ./..., bash -n scripts/*.sh,\nand make build.
125 lines
4.9 KiB
Go
125 lines
4.9 KiB
Go
package daemon
|
|
|
|
import (
|
|
"context"
|
|
"strings"
|
|
|
|
"banger/internal/model"
|
|
"banger/internal/system"
|
|
)
|
|
|
|
var vsockHostDevicePath = "/dev/vhost-vsock"
|
|
|
|
func (d *Daemon) validateStartPrereqs(ctx context.Context, vm model.VMRecord, image model.Image) error {
|
|
checks := system.NewPreflight()
|
|
d.addBaseStartPrereqs(checks, image)
|
|
d.addCapabilityStartPrereqs(ctx, checks, vm, image)
|
|
return checks.Err("vm start preflight failed")
|
|
}
|
|
|
|
func (d *Daemon) validateImageBuildPrereqs(ctx context.Context, baseRootfs, kernelPath, initrdPath, modulesDir, sizeSpec string) error {
|
|
checks := system.NewPreflight()
|
|
d.addImageBuildPrereqs(ctx, checks, baseRootfs, kernelPath, initrdPath, modulesDir, sizeSpec)
|
|
return checks.Err("image build preflight failed")
|
|
}
|
|
|
|
func (d *Daemon) validateWorkDiskResizePrereqs() error {
|
|
checks := system.NewPreflight()
|
|
checks.RequireCommand("truncate", toolHint("truncate"))
|
|
checks.RequireCommand("e2fsck", `install e2fsprogs`)
|
|
checks.RequireCommand("resize2fs", `install e2fsprogs`)
|
|
return checks.Err("work disk resize preflight failed")
|
|
}
|
|
|
|
func (d *Daemon) addNATPrereqs(ctx context.Context, checks *system.Preflight) {
|
|
checks.RequireCommand("iptables", toolHint("iptables"))
|
|
checks.RequireCommand("sysctl", toolHint("sysctl"))
|
|
runner := d.runner
|
|
if runner == nil {
|
|
runner = system.NewRunner()
|
|
}
|
|
out, err := runner.Run(ctx, "ip", "route", "show", "default")
|
|
if err != nil {
|
|
checks.Addf("failed to inspect the default route for NAT: %v", err)
|
|
return
|
|
}
|
|
if _, err := parseDefaultUplink(string(out)); err != nil {
|
|
checks.Addf("failed to detect the uplink interface for NAT: %v", err)
|
|
}
|
|
}
|
|
|
|
func (d *Daemon) addBaseStartPrereqs(checks *system.Preflight, image model.Image) {
|
|
d.addBaseStartCommandPrereqs(checks)
|
|
checks.RequireExecutable(d.config.FirecrackerBin, "firecracker binary", `install firecracker or set "firecracker_bin"`)
|
|
if helper, err := d.vsockAgentBinary(); err == nil {
|
|
checks.RequireExecutable(helper, "vsock agent helper", `run 'make build' or reinstall banger`)
|
|
} else {
|
|
checks.Addf("%v", err)
|
|
}
|
|
checks.RequireFile(vsockHostDevicePath, "vsock host device", "load the vhost_vsock kernel module on the host")
|
|
checks.RequireFile(image.RootfsPath, "rootfs image", "select a valid registered image")
|
|
checks.RequireFile(image.KernelPath, "kernel image", `re-register or rebuild the image with a valid kernel`)
|
|
if strings.TrimSpace(image.InitrdPath) != "" {
|
|
checks.RequireFile(image.InitrdPath, "initrd image", `re-register or rebuild the image with a valid initrd`)
|
|
}
|
|
}
|
|
|
|
func (d *Daemon) addBaseStartCommandPrereqs(checks *system.Preflight) {
|
|
for _, command := range []string{"sudo", "ip", "dmsetup", "losetup", "blockdev", "truncate", "pgrep", "chown", "chmod", "kill", "e2cp", "e2rm", "debugfs"} {
|
|
checks.RequireCommand(command, toolHint(command))
|
|
}
|
|
}
|
|
|
|
func (d *Daemon) addImageBuildPrereqs(ctx context.Context, checks *system.Preflight, baseRootfs, kernelPath, initrdPath, modulesDir, sizeSpec string) {
|
|
for _, command := range []string{"sudo", "ip", "pgrep", "chown", "chmod", "kill"} {
|
|
checks.RequireCommand(command, toolHint(command))
|
|
}
|
|
for _, command := range []string{"mkfs.ext4", "mount", "umount", "cp"} {
|
|
checks.RequireCommand(command, toolHint(command))
|
|
}
|
|
checks.RequireExecutable(d.config.FirecrackerBin, "firecracker binary", `install firecracker or set "firecracker_bin"`)
|
|
checks.RequireFile(d.config.SSHKeyPath, "ssh private key", `set "ssh_key_path" or let banger create its default key`)
|
|
if helper, err := d.vsockAgentBinary(); err == nil {
|
|
checks.RequireExecutable(helper, "vsock agent helper", `run 'make build' or reinstall banger`)
|
|
} else {
|
|
checks.Addf("%v", err)
|
|
}
|
|
checks.RequireFile(baseRootfs, "base image rootfs", `pass --from-image with a valid registered image`)
|
|
checks.RequireFile(kernelPath, "kernel image", `pass --kernel or build from an image with a valid kernel`)
|
|
if strings.TrimSpace(initrdPath) != "" {
|
|
checks.RequireFile(initrdPath, "initrd image", `pass --initrd or build from an image with a valid initrd`)
|
|
}
|
|
if strings.TrimSpace(modulesDir) != "" {
|
|
checks.RequireDir(modulesDir, "modules directory", `pass --modules or build from an image with a valid modules dir`)
|
|
}
|
|
if strings.TrimSpace(sizeSpec) != "" {
|
|
checks.RequireCommand("e2fsck", toolHint("e2fsck"))
|
|
checks.RequireCommand("resize2fs", toolHint("resize2fs"))
|
|
}
|
|
d.addNATPrereqs(ctx, checks)
|
|
}
|
|
|
|
func toolHint(command string) string {
|
|
switch command {
|
|
case "ip":
|
|
return "install iproute2"
|
|
case "iptables":
|
|
return "install iptables"
|
|
case "sysctl", "losetup", "blockdev", "mount", "umount":
|
|
return "install util-linux"
|
|
case "dmsetup":
|
|
return "install device-mapper"
|
|
case "pgrep", "kill":
|
|
return "install procps"
|
|
case "chown", "chmod", "cp", "truncate":
|
|
return "install coreutils"
|
|
case "e2fsck", "resize2fs", "debugfs", "mkfs.ext4":
|
|
return "install e2fsprogs"
|
|
case "e2cp", "e2rm":
|
|
return "install e2tools"
|
|
case "sudo":
|
|
return "install sudo"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|