server init and mirror init took the first non-loopback address for the mirror's --base, Docker's 172.17.0.1 on a machine with Docker; nodes asked their own bridge for every model and were refused. primaryAddr takes the default route's source, else the first address on an interface that is not a container's, bridge's or overlay's. node add has the node reach the mirror's files during the checks and fails, naming the address and the fix, when it cannot. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
194 lines
5.8 KiB
Go
194 lines
5.8 KiB
Go
package cli
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"os"
|
|
"path/filepath"
|
|
"slices"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/config"
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
|
|
)
|
|
|
|
func newTestInit(t *testing.T) (*serverInit, *bytes.Buffer) {
|
|
t.Helper()
|
|
root := t.TempDir()
|
|
var out bytes.Buffer
|
|
return &serverInit{
|
|
etcDir: filepath.Join(root, "etc"),
|
|
stateDir: filepath.Join(root, "state"),
|
|
pkiDir: filepath.Join(root, "etc", "pki"),
|
|
admin: "admin@example.com",
|
|
out: &out,
|
|
}, &out
|
|
}
|
|
|
|
func TestInitLeavesAControlPlaneThatStarts(t *testing.T) {
|
|
in, out := newTestInit(t)
|
|
if err := in.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
|
|
cfg, err := config.Load(in.configPath())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// The configuration install.md used to show had an empty catalog and no
|
|
// control.enabled, which the server refuses as having nothing to serve.
|
|
if !cfg.ControlPlaneMode() {
|
|
t.Error("the written configuration does not run a control plane")
|
|
}
|
|
if !cfg.AgentTLS.Enabled() || !cfg.Auth.Enabled {
|
|
t.Error("mutual TLS and authentication should both be on")
|
|
}
|
|
for _, f := range []string{"ca.pem", "server.pem", "server-key.pem"} {
|
|
if _, err := os.Stat(filepath.Join(in.etcDir, f)); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
s, err := store.Open(context.Background(), cfg.Auth.Store)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer s.Close()
|
|
u, err := s.UserByEmail(context.Background(), "admin@example.com")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
inDefault, _ := s.CanUseProject(context.Background(), u.ID, "default")
|
|
if !u.IsAdmin || u.State != store.UserActive || !inDefault {
|
|
t.Errorf("administrator not ready to use: %+v", u)
|
|
}
|
|
if !strings.Contains(out.String(), "password: ") {
|
|
t.Error("the generated password was not shown")
|
|
}
|
|
}
|
|
|
|
func TestInitAgainChangesNothing(t *testing.T) {
|
|
in, out := newTestInit(t)
|
|
if err := in.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
cert, _ := os.ReadFile(filepath.Join(in.etcDir, "server.pem"))
|
|
|
|
again := *in
|
|
again.changed = false
|
|
out.Reset()
|
|
if err := again.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
if again.changed {
|
|
t.Errorf("a second run changed something:\n%s", out)
|
|
}
|
|
if strings.Contains(out.String(), "password: ") {
|
|
t.Error("a second run must not reset the administrator's password")
|
|
}
|
|
if now, _ := os.ReadFile(filepath.Join(in.etcDir, "server.pem")); !bytes.Equal(now, cert) {
|
|
t.Error("the certificate was reissued without reason")
|
|
}
|
|
}
|
|
|
|
func TestInitWithANewHostKeepsTheOldOnes(t *testing.T) {
|
|
in, out := newTestInit(t)
|
|
in.hosts = []string{"old.internal"}
|
|
if err := in.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
in.hosts = []string{"new.internal"}
|
|
if err := in.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
cert, err := readCert(filepath.Join(in.etcDir, "server.pem"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for _, h := range []string{"old.internal", "new.internal"} {
|
|
if !slices.Contains(cert.DNSNames, h) {
|
|
t.Errorf("certificate lost %s: %v", h, cert.DNSNames)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestInitNeverOverwritesTheConfiguration(t *testing.T) {
|
|
in, out := newTestInit(t)
|
|
if err := os.MkdirAll(in.etcDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
mine := "# mine\ncontrol:\n enabled: true\nauth:\n enabled: true\n store: " +
|
|
filepath.Join(in.stateDir, "mine.db") + "\n"
|
|
if err := os.WriteFile(in.configPath(), []byte(mine), 0o640); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := in.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
if got, _ := os.ReadFile(in.configPath()); string(got) != mine {
|
|
t.Error("an existing server.yaml was rewritten")
|
|
}
|
|
// And the store it names is the one used.
|
|
if _, err := os.Stat(filepath.Join(in.stateDir, "mine.db")); err != nil {
|
|
t.Error(err)
|
|
}
|
|
}
|
|
|
|
func TestTheInitUnitIsTheShippedUnit(t *testing.T) {
|
|
b, err := os.ReadFile("../../deploy/systemd/llmgw-server.service")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if string(b) != serverUnit {
|
|
t.Error("deploy/systemd/llmgw-server.service and the unit 'server init' writes have drifted")
|
|
}
|
|
}
|
|
|
|
func TestInitKeepsCertificatesFromAnAuthorityElsewhere(t *testing.T) {
|
|
in, out := newTestInit(t)
|
|
// Issued on another machine by an authority that never comes here.
|
|
elsewhere := &serverInit{etcDir: in.etcDir, pkiDir: filepath.Join(t.TempDir(), "pki"), out: &bytes.Buffer{}}
|
|
if err := os.MkdirAll(in.etcDir, 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := elsewhere.ensureCerts(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
before, _ := os.ReadFile(filepath.Join(in.etcDir, "server.pem"))
|
|
|
|
if err := in.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
if after, _ := os.ReadFile(filepath.Join(in.etcDir, "server.pem")); !bytes.Equal(before, after) {
|
|
t.Error("a certificate from another authority was replaced")
|
|
}
|
|
if _, err := os.Stat(filepath.Join(in.pkiDir, "ca-key.pem")); err == nil {
|
|
t.Error("an authority was created beside one that already exists elsewhere")
|
|
}
|
|
|
|
in.hosts = []string{"new.internal"}
|
|
if err := in.run(context.Background()); err == nil {
|
|
t.Error("--host cannot be honoured without the authority, and should say so")
|
|
}
|
|
}
|
|
|
|
func TestTheAddressNodesReachIsNotAContainersBridge(t *testing.T) {
|
|
if got := routeSource("1.1.1.1 via 10.104.130.129 dev ens192 src 10.104.130.140 uid 0\n cache\n"); got != "10.104.130.140" {
|
|
t.Errorf("route source %q", got)
|
|
}
|
|
if got := routeSource("unreachable"); got != "" {
|
|
t.Errorf("no route: %q", got)
|
|
}
|
|
for _, name := range []string{"docker0", "br-3f2a", "virbr0", "veth12ab", "cni0", "flannel.1"} {
|
|
if !virtualInterface(name) {
|
|
t.Errorf("%s taken for a real interface", name)
|
|
}
|
|
}
|
|
for _, name := range []string{"eth0", "ens192", "enp3s0", "bond0", "ib0"} {
|
|
if virtualInterface(name) {
|
|
t.Errorf("%s taken for a virtual one", name)
|
|
}
|
|
}
|
|
}
|