incus: syntax-check the generated install script for each machine shape; refusals; create args
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
289aa4aee3
commit
dfe2ca359a
@@ -0,0 +1,90 @@
|
|||||||
|
package incus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os/exec"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The install script is generated, so a quoting slip would only show on a live machine.
|
||||||
|
// Build it for the shapes of machine we have and let sh check the syntax.
|
||||||
|
func TestInstallScriptShapes(t *testing.T) {
|
||||||
|
if _, err := exec.LookPath("sh"); err != nil {
|
||||||
|
t.Skip("no sh")
|
||||||
|
}
|
||||||
|
m := New("/home/core/apps/hamlab", "core", "test")
|
||||||
|
cases := []struct {
|
||||||
|
name string
|
||||||
|
st Status
|
||||||
|
o InstallOpts
|
||||||
|
want []string
|
||||||
|
}{
|
||||||
|
{"grid: zfs, apt, docker", Status{State: "installable", PM: "apt", Arch: "x86_64", Drivers: []string{"zfs", "btrfs", "dir"}, Docker: true, ZFSHost: true, DiskFree: 700 << 30, MemTotal: 62 << 30},
|
||||||
|
InstallOpts{Driver: "zfs", PoolSizeGiB: 300, Subnet: "172.16.100.1/24", DockerRules: true, ARCMaxGiB: 16},
|
||||||
|
[]string{"apt-get", "zpool create", "incus storage create default zfs source=hamlab-virt", "ipv4.address='172.16.100.1/24'", "DOCKER-USER", "zfs_arc_max", "usermod -aG incus-admin 'core'", "SupplementaryGroups=incus-admin", "systemd-run"}},
|
||||||
|
{"core: btrfs, apt, docker, no tools yet", Status{State: "installable", PM: "apt", Arch: "x86_64", Drivers: []string{"btrfs", "dir"}, Docker: true, DiskFree: 170 << 30, MemTotal: 8 << 30},
|
||||||
|
InstallOpts{Driver: "btrfs", PoolSizeGiB: 40, Subnet: "172.16.100.1/24", DockerRules: true},
|
||||||
|
[]string{"btrfs-progs", "mkfs.btrfs", "/etc/fstab", "incus storage create default btrfs source="}},
|
||||||
|
{"mac: dir, dnf, arm64", Status{State: "installable", PM: "dnf", Arch: "aarch64", Drivers: []string{"dir"}, DiskFree: 200 << 30, MemTotal: 15 << 30},
|
||||||
|
InstallOpts{Driver: "dir", Subnet: "172.16.101.1/24"},
|
||||||
|
[]string{"dnf -y install incus qemu-system-aarch64-core edk2-aarch64", "incus storage create default dir source="}},
|
||||||
|
{"repair: already installed", Status{State: "repair", PM: "apt", Arch: "x86_64", Drivers: []string{"dir"}, DiskFree: 10 << 30, MemTotal: 4 << 30},
|
||||||
|
InstallOpts{Driver: "dir", Subnet: "172.16.100.1/24"},
|
||||||
|
[]string{"already installed"}},
|
||||||
|
}
|
||||||
|
for _, c := range cases {
|
||||||
|
script, lay, err := m.InstallScript(c.st, c.o)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("%s: %v", c.name, err)
|
||||||
|
}
|
||||||
|
for _, w := range c.want {
|
||||||
|
if !strings.Contains(script, w) {
|
||||||
|
t.Errorf("%s: script lacks %q", c.name, w)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if lay.Driver != c.o.Driver || lay.Subnet != c.o.Subnet {
|
||||||
|
t.Errorf("%s: layout %+v", c.name, lay)
|
||||||
|
}
|
||||||
|
cmd := exec.Command("sh", "-n")
|
||||||
|
cmd.Stdin = strings.NewReader(script)
|
||||||
|
if out, err := cmd.CombinedOutput(); err != nil {
|
||||||
|
t.Errorf("%s: sh -n: %v\n%s", c.name, err, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestInstallScriptRefusals(t *testing.T) {
|
||||||
|
m := New("/x", "core", "test")
|
||||||
|
st := Status{State: "installable", PM: "apt", Drivers: []string{"btrfs", "dir"}, DiskFree: 20 << 30, MemTotal: 8 << 30}
|
||||||
|
for _, o := range []InstallOpts{
|
||||||
|
{Driver: "zfs", PoolSizeGiB: 10, Subnet: "172.16.100.1/24"}, // not offered here
|
||||||
|
{Driver: "btrfs", PoolSizeGiB: 50, Subnet: "172.16.100.1/24"}, // more than is free
|
||||||
|
{Driver: "btrfs", PoolSizeGiB: 10, Subnet: "172.16.100.0/24"}, // the network address, not the bridge's
|
||||||
|
{Driver: "btrfs", PoolSizeGiB: 10, Subnet: "10.0.0.1/8"}, // too wide
|
||||||
|
{Driver: "btrfs", PoolSizeGiB: 10, Subnet: "172.16.100.1/24", ARCMaxGiB: 64}, // more RAM than there is
|
||||||
|
} {
|
||||||
|
if _, _, err := m.InstallScript(st, o); err == nil {
|
||||||
|
t.Errorf("accepted %+v", o)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestCreateArgs(t *testing.T) {
|
||||||
|
args, err := CreateArgs(CreateSpec{Name: "web-1", Image: "images:debian/13", VM: true, CPU: "2", Memory: "2GiB", Disk: "20GiB", Network: "incusbr0", Start: true}, true)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
want := "launch images:debian/13 web-1 --vm -c limits.cpu=2 -c limits.memory=2GiB -d root,size=20GiB -n incusbr0"
|
||||||
|
if got := strings.Join(args, " "); got != want {
|
||||||
|
t.Fatalf("got %q", got)
|
||||||
|
}
|
||||||
|
if _, err := CreateArgs(CreateSpec{Name: "web-1", Image: "images:debian/13", VM: true}, false); err == nil {
|
||||||
|
t.Fatal("a VM without KVM must be refused")
|
||||||
|
}
|
||||||
|
if _, err := CreateArgs(CreateSpec{Name: "1bad", Image: "images:debian/13"}, true); err == nil {
|
||||||
|
t.Fatal("a name starting with a digit must be refused")
|
||||||
|
}
|
||||||
|
if _, err := CreateArgs(CreateSpec{Name: "ok", Image: "images:debian/13", Memory: "2 gigs"}, true); err == nil {
|
||||||
|
t.Fatal("a malformed size must be refused")
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user