kvm2: config block, constructor registration, IDs, state mapping and classify
The kvm2 block reuses KVMConfig; validateKVM gains a block-name variant so messages say kvm2. The package skeleton has a non-dialing New, strict providerID parsing, the state table and a 34-row classify test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -214,6 +214,100 @@ providers:
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfig_kvm2Valid(t *testing.T) {
|
||||
t.Parallel()
|
||||
yaml := strings.Replace(validKVMYAML, "type: kvm\n kvm:\n", "type: kvm2\n kvm2:\n", 1)
|
||||
cfg, err := LoadConfig([]byte(yaml))
|
||||
if err != nil {
|
||||
t.Fatalf("LoadConfig() error = %v, want nil", err)
|
||||
}
|
||||
if cfg.Providers[0].KVM != nil {
|
||||
t.Errorf("providers[0].kvm = %+v, want nil", cfg.Providers[0].KVM)
|
||||
}
|
||||
k := cfg.Providers[0].KVM2
|
||||
if k == nil {
|
||||
t.Fatal("providers[0].kvm2 = nil")
|
||||
}
|
||||
if k.SSHKeyFile != "/etc/proxy-operator/kvm/id_ed25519" || k.KnownHostsFile != "/etc/proxy-operator/kvm/known_hosts" || k.DiskSizeGB != 20 {
|
||||
t.Errorf("kvm2 = %+v, want sshKeyFile, knownHostsFile and diskSizeGb parsed", k)
|
||||
}
|
||||
if k.Images["ubuntu"].Format != "raw" {
|
||||
t.Errorf("images[ubuntu].format = %q, want raw", k.Images["ubuntu"].Format)
|
||||
}
|
||||
if mt := k.MachineTypes["small"]; mt.VCPUs != 1 || mt.MemoryMiB != 1024 {
|
||||
t.Errorf("machineTypes[small] = %+v, want {1 1024}", mt)
|
||||
}
|
||||
if len(k.Hosts) != 2 || k.Hosts[0].Name != "nas1" || k.Hosts[1].Pool != "fast" {
|
||||
t.Errorf("hosts = %+v, want nas1 and lab2 with lab2's pool parsed", k.Hosts)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLoadConfig_kvm2Invalid(t *testing.T) {
|
||||
t.Parallel()
|
||||
minimal := func(body string) string {
|
||||
return "providers:\n - name: kvm2-home\n type: kvm2\n kvm2:\n" + indent(body, 6)
|
||||
}
|
||||
hostsAndTypes := `
|
||||
machineTypes:
|
||||
small: {vcpus: 1, memoryMiB: 1024}
|
||||
hosts:
|
||||
- {name: nas1, address: nas1:22, user: virt, bridge: br0}
|
||||
`
|
||||
tests := []struct {
|
||||
name string
|
||||
yaml string
|
||||
wantErrSub string
|
||||
}{
|
||||
{
|
||||
name: "missing kvm2 block",
|
||||
yaml: "providers:\n - name: kvm2-home\n type: kvm2\n",
|
||||
wantErrSub: "kvm2 block is required",
|
||||
},
|
||||
{
|
||||
name: "missing sshKeyFile",
|
||||
yaml: minimal("knownHostsFile: /kh\n" + hostsAndTypes),
|
||||
wantErrSub: "kvm2.sshKeyFile is required",
|
||||
},
|
||||
{
|
||||
name: "missing knownHostsFile without insecure flag",
|
||||
yaml: minimal("sshKeyFile: /key\n" + hostsAndTypes),
|
||||
wantErrSub: "kvm2.knownHostsFile is required unless kvm2.insecureIgnoreHostKey is true",
|
||||
},
|
||||
{
|
||||
name: "no machine types",
|
||||
yaml: minimal("sshKeyFile: /key\nknownHostsFile: /kh\nhosts:\n - {name: nas1, address: nas1:22, user: virt, bridge: br0}\n"),
|
||||
wantErrSub: "kvm2.machineTypes must define at least one",
|
||||
},
|
||||
{
|
||||
name: "no hosts",
|
||||
yaml: minimal("sshKeyFile: /key\nknownHostsFile: /kh\nmachineTypes:\n small: {vcpus: 1, memoryMiB: 1024}\n"),
|
||||
wantErrSub: "kvm2.hosts must list at least one host",
|
||||
},
|
||||
{
|
||||
name: "duplicate host name",
|
||||
yaml: minimal("sshKeyFile: /key\nknownHostsFile: /kh\nmachineTypes:\n small: {vcpus: 1, memoryMiB: 1024}\nhosts:\n - {name: nas1, address: a:22, user: virt, bridge: br0}\n - {name: nas1, address: b:22, user: virt, bridge: br0}\n"),
|
||||
wantErrSub: `kvm2.hosts[1]: duplicate host name "nas1"`,
|
||||
},
|
||||
{
|
||||
name: "image key with a slash",
|
||||
yaml: minimal("sshKeyFile: /key\nknownHostsFile: /kh\nimages:\n ../etc/d: {url: https://x/y.qcow2}\n" + hostsAndTypes),
|
||||
wantErrSub: `kvm2.images["../etc/d"]: key must be letters, digits, dots, dashes or underscores`,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
t.Parallel()
|
||||
_, err := LoadConfig([]byte(tc.yaml))
|
||||
if err == nil {
|
||||
t.Fatalf("LoadConfig() error = nil, want error containing %q", tc.wantErrSub)
|
||||
}
|
||||
if !strings.Contains(err.Error(), tc.wantErrSub) {
|
||||
t.Errorf("LoadConfig() error = %q, want substring %q", err.Error(), tc.wantErrSub)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func indent(s string, n int) string {
|
||||
pad := strings.Repeat(" ", n)
|
||||
lines := strings.Split(strings.TrimLeft(s, "\n"), "\n")
|
||||
|
||||
Reference in New Issue
Block a user