With nothing installed, sudo llmgw asks for one machine or three, takes how to reach the other two (ssh agent, key or password, and a sudo password used only for the install), checks every machine first, shows the plan and its command line, and installs. On a control plane it opens a console with the cluster's state and the next steps. Machines are reached with Go's ssh so a password works; the store's etcd and access rules use this machine's routed address rather than a client-facing name. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
110 lines
3.5 KiB
Go
110 lines
3.5 KiB
Go
package preflight
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"strconv"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/onboard"
|
|
)
|
|
|
|
func facts(over map[string]string) map[string]string {
|
|
f := map[string]string{
|
|
"os": "ubuntu", "version": "24.04", "pretty": "Ubuntu 24.04.3 LTS", "arch": "x86_64",
|
|
"cpus": "2", "mem_mb": "3900", "disk_gb": "35", "ntp": "yes", "listening": "22 53",
|
|
"sudo": "yes", "apt": "yes", "internet": "yes",
|
|
"now": strconv.FormatFloat(float64(time.Now().UnixNano())/1e9, 'f', 3, 64),
|
|
}
|
|
for k, v := range over {
|
|
f[k] = v
|
|
}
|
|
return f
|
|
}
|
|
|
|
func levelOf(fs []Finding, check string) (Level, string) {
|
|
for _, f := range fs {
|
|
if f.Check == check {
|
|
return f.Level, f.Detail
|
|
}
|
|
}
|
|
return -1, ""
|
|
}
|
|
|
|
func TestAMachineFitForItsRoleHasNothingWrong(t *testing.T) {
|
|
fs := Evaluate(Machine{Name: "pg01", Roles: []Role{RoleDatabase}}, facts(nil), time.Now())
|
|
if r := (Report{Findings: fs}); r.Worst() != OK {
|
|
t.Errorf("%+v", fs)
|
|
}
|
|
}
|
|
|
|
func TestEachProblemIsFoundAndSaysWhatToDo(t *testing.T) {
|
|
m := Machine{Name: "x", Roles: []Role{RoleDatabase, RoleControl}}
|
|
cases := []struct {
|
|
over map[string]string
|
|
check string
|
|
want Level
|
|
}{
|
|
{map[string]string{"os": "centos", "version": "9"}, "system", Fail},
|
|
{map[string]string{"version": "20.04"}, "system", Warn},
|
|
{map[string]string{"arch": "riscv64"}, "architecture", Fail},
|
|
{map[string]string{"sudo": "no"}, "sudo", Warn},
|
|
{map[string]string{"mem_mb": "1000"}, "memory", Fail},
|
|
{map[string]string{"disk_gb": "20"}, "disk", Warn},
|
|
{map[string]string{"ntp": "no"}, "time sync", Warn},
|
|
{map[string]string{"listening": "22 5432"}, "ports", Warn},
|
|
{map[string]string{"internet": "no"}, "internet", Fail},
|
|
{map[string]string{"now": strconv.FormatFloat(float64(time.Now().Add(-30*time.Second).UnixNano())/1e9, 'f', 3, 64)}, "clock", Fail},
|
|
}
|
|
for _, c := range cases {
|
|
fs := Evaluate(m, facts(c.over), time.Now())
|
|
got, detail := levelOf(fs, c.check)
|
|
if got != c.want {
|
|
t.Errorf("%v: %s is %v (%s), want %v", c.over, c.check, got, detail, c.want)
|
|
}
|
|
for _, f := range fs {
|
|
if f.Level != OK && f.Fix == "" {
|
|
t.Errorf("%s: %s says nothing about what to do", c.check, f.Check)
|
|
}
|
|
}
|
|
}
|
|
// This machine is run as root; sudo is not its question.
|
|
if l, _ := levelOf(Evaluate(Machine{Name: "here", Local: true}, facts(map[string]string{"sudo": "no"}), time.Now()), "sudo"); l != -1 {
|
|
t.Error("the local machine was asked about sudo")
|
|
}
|
|
}
|
|
|
|
func TestAMachineThatCannotReachAnotherIsCalledOut(t *testing.T) {
|
|
fs := evaluateReach(Machine{Name: "a"}, "reach 10.0.0.2 yes\nreach 10.0.0.3 no\n")
|
|
if fs[0].Level != Fail || !strings.Contains(fs[0].Detail, "10.0.0.3") {
|
|
t.Errorf("%+v", fs)
|
|
}
|
|
}
|
|
|
|
// TestAgainstRealMachines runs the probe over ssh when LLMGW_TEST_PREFLIGHT
|
|
// names user@host,user@host: the scripts are shell, and only a real machine
|
|
// says whether they parse.
|
|
func TestAgainstRealMachines(t *testing.T) {
|
|
targets := os.Getenv("LLMGW_TEST_PREFLIGHT")
|
|
if targets == "" {
|
|
t.Skip("set LLMGW_TEST_PREFLIGHT=user@host,user@host to run against machines")
|
|
}
|
|
var ms []Machine
|
|
for _, tgt := range strings.Split(targets, ",") {
|
|
user, host, _ := strings.Cut(tgt, "@")
|
|
ms = append(ms, Machine{Name: host, Addr: host, Roles: []Role{RoleDatabase},
|
|
Remote: &onboard.GoSSH{Addr: host, User: user, UseAgent: true}})
|
|
}
|
|
rep := Run(context.Background(), ms)
|
|
for _, f := range rep.Findings {
|
|
t.Logf("%-12s %-12s %-5s %s", f.Machine, f.Check, f.Level, f.Detail)
|
|
}
|
|
for _, f := range rep.Findings {
|
|
if f.Check == "login" && f.Level != OK {
|
|
t.Fatalf("could not log in: %s", f.Detail)
|
|
}
|
|
}
|
|
}
|