feat: Phase 7 — SeedService, SecretsService, ProvisioningService + ssh Provisioner
Seed ingest/export moves behind ports.SeedRepository (SeedRepo in the postgres adapter; knowledge ingest absorbed from internal/knowledge, package deleted). pct_create flow (defaults, template/VMID/gateway pre-flights, pct create, graph registration) moves from httpapi's approved-execution path into app.ProvisioningService + the ssh provisioner adapter; CLI seed/export/secret become adapters over the services. EntityCreateInput gains EnrolledAt. Plan status corrected: phases 0-7 shipped, 8 + 9 gates open. VERSION 0.34.1.
This commit is contained in:
100
internal/adapters/ssh/provisioner_test.go
Normal file
100
internal/adapters/ssh/provisioner_test.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package ssh
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/dtoro/oikos/internal/core/ports"
|
||||
)
|
||||
|
||||
// TestResolveTemplate — moved from httpapi/pct_create_test.go with the
|
||||
// pct flow it belongs to.
|
||||
func TestResolveTemplate(t *testing.T) {
|
||||
avail := []string{
|
||||
"debian-12-standard_12.7-1_amd64.tar.zst",
|
||||
"debian-13-standard_13.0-1_amd64.tar.zst",
|
||||
"ubuntu-24.04-standard_24.04-2_amd64.tar.zst",
|
||||
}
|
||||
cases := []struct {
|
||||
requested string
|
||||
want string
|
||||
}{
|
||||
{"debian-13-standard_13.0-1_amd64.tar.zst", "debian-13-standard_13.0-1_amd64.tar.zst"}, // exact
|
||||
{"debian-13", "debian-13-standard_13.0-1_amd64.tar.zst"}, // prefix
|
||||
{"", "debian-13-standard_13.0-1_amd64.tar.zst"}, // auto newest debian
|
||||
{"debian-99", "debian-13-standard_13.0-1_amd64.tar.zst"}, // miss prefix → auto debian
|
||||
{"ubuntu-24", "ubuntu-24.04-standard_24.04-2_amd64.tar.zst"},
|
||||
{"alpine", "debian-13-standard_13.0-1_amd64.tar.zst"}, // miss → auto debian
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := ResolveTemplate(c.requested, avail); got != c.want {
|
||||
t.Errorf("ResolveTemplate(%q) = %q, want %q", c.requested, got, c.want)
|
||||
}
|
||||
}
|
||||
if got := ResolveTemplate("debian", nil); got != "" {
|
||||
t.Errorf("ResolveTemplate with no cache = %q, want empty", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGatewayPreflightPassed(t *testing.T) {
|
||||
cases := []struct {
|
||||
in string
|
||||
want bool
|
||||
}{
|
||||
{"PREFLIGHT_OK", true},
|
||||
{"PREFLIGHT_OK\n", true},
|
||||
{" PREFLIGHT_OK ", true},
|
||||
{"PREFLIGHT_FAIL", false},
|
||||
{"UNREACHABLE", false}, // the original substring bug
|
||||
{"", false},
|
||||
}
|
||||
for _, c := range cases {
|
||||
if got := GatewayPreflightPassed(c.in); got != c.want {
|
||||
t.Errorf("GatewayPreflightPassed(%q) = %v, want %v", c.in, got, c.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuildPctCreateCmd(t *testing.T) {
|
||||
base := ports.LXCInput{
|
||||
VMID: 137, Hostname: "grafana", Cores: 2, MemoryMB: 1024, DiskGB: 12,
|
||||
IP: "192.168.8.55", GW: "192.168.8.2", Bridge: "vmbr1",
|
||||
Storage: "local-lvm", Template: "debian-13-standard_13.0-1_amd64.tar.zst",
|
||||
Nameserver: "192.168.8.2", Searchdomain: "hubris.network",
|
||||
}
|
||||
got := BuildPctCreateCmd(base)
|
||||
for _, want := range []string{
|
||||
"pct create 137 /var/lib/vz/template/cache/debian-13-standard_13.0-1_amd64.tar.zst",
|
||||
"--hostname grafana",
|
||||
"--cores 2",
|
||||
"--memory 1024",
|
||||
"--rootfs local-lvm:12",
|
||||
"--unprivileged 1",
|
||||
"--net0 name=eth0,bridge=vmbr1,ip=192.168.8.55,gw=192.168.8.2",
|
||||
"--start 1",
|
||||
"--nameserver 192.168.8.2",
|
||||
"--searchdomain hubris.network",
|
||||
} {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("cmd missing %q:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
if strings.Contains(got, "--features") {
|
||||
t.Errorf("unprivileged non-nested should have no features flag:\n%s", got)
|
||||
}
|
||||
|
||||
nested := base
|
||||
nested.Nesting = true
|
||||
nested.Privileged = true
|
||||
nested.IP = "dhcp"
|
||||
got = BuildPctCreateCmd(nested)
|
||||
if !strings.Contains(got, "--features nesting=1,keyctl=1") {
|
||||
t.Errorf("privileged+nesting features missing:\n%s", got)
|
||||
}
|
||||
if !strings.Contains(got, "--unprivileged 0") {
|
||||
t.Errorf("privileged should pass --unprivileged 0:\n%s", got)
|
||||
}
|
||||
if !strings.Contains(got, "ip=dhcp") || strings.Contains(got, "gw=") {
|
||||
t.Errorf("dhcp must omit gateway:\n%s", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user