`llmgw server init` does what install.md's steps 2 and 3 asked of the operator: the llmgw user and directories, a certificate authority, the control plane's certificate for every address the machine has, a configuration, the default project, an administrator with a generated password, and the systemd unit — then starts it and waits for /health. Every step looks before it acts, so a second run changes nothing, and --host later reissues the certificate with the old names kept. It never overwrites server.yaml or an authority, and leaves alone certificates issued by an authority kept on another machine. The configuration install.md showed could not start: an empty catalog without control.enabled is refused as having nothing to serve. The one init writes sets it, and a test holds that. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
174 lines
5.1 KiB
Go
174 lines
5.1 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)
|
|
}
|
|
if !u.IsAdmin || u.State != store.UserActive || u.ProjectID != "default" {
|
|
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")
|
|
}
|
|
}
|