A bundle carries what a cluster would download — llmgw's release with its signed checksums, every llama.cpp build per architecture with GitHub's checksums, model files pinned and checked against Hugging Face's — into a directory or a tar whose manifest sha256 is carried apart. Import checks everything, the release against the signing key, before anything is put in the mirror. With offline.mirror set, nodes install llama.cpp from the mirror against checksums the control plane holds and sends over the agent stream; releases default to the mirror for node add, ctl upgrade and agent upgrades. server init and the setup form install from a bundle. The Helm chart runs one control plane with SQLite on a claim or an external PostgreSQL, Secrets for the agent certificate and admin token, Services, Ingress and ServiceMonitor; deploy/container/Dockerfile builds its image. GPU nodes stay outside Kubernetes, as docs/kubernetes.md explains. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
87 lines
3.0 KiB
Go
87 lines
3.0 KiB
Go
package cli
|
|
|
|
import (
|
|
"context"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/bundle"
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/config"
|
|
)
|
|
|
|
// handMadeBundle is a bundle as 'bundle create' leaves it: an engine build
|
|
// and the starter model, with their checksums in the manifest.
|
|
func handMadeBundle(t *testing.T) (dir, digest string) {
|
|
t.Helper()
|
|
dir = t.TempDir()
|
|
m := bundle.Manifest{Format: bundle.Format, MadeBy: "test",
|
|
Models: []bundle.Model{{Name: starterName, Version: starterVersion, Source: starterSource}}}
|
|
for p, body := range map[string]string{
|
|
"engines/llamacpp/b1/llama-b1-bin-ubuntu-x64.tar.gz": "an engine",
|
|
"models/" + starterName + "/" + starterVersion + "/qwen-q4_k_m.gguf": "weights",
|
|
} {
|
|
full := filepath.Join(dir, p)
|
|
_ = os.MkdirAll(filepath.Dir(full), 0o755)
|
|
_ = os.WriteFile(full, []byte(body), 0o644)
|
|
sum := sha256.Sum256([]byte(body))
|
|
m.Files = append(m.Files, bundle.File{Path: p, Bytes: int64(len(body)), SHA256: hex.EncodeToString(sum[:])})
|
|
}
|
|
raw, _ := json.Marshal(m)
|
|
_ = os.WriteFile(filepath.Join(dir, bundle.ManifestName), raw, 0o644)
|
|
return dir, bundle.Digest(raw)
|
|
}
|
|
|
|
func TestInitFromABundleLeavesAnOfflineClusterThatTrustsItsEngines(t *testing.T) {
|
|
in, out := newTestInit(t)
|
|
dir, digest := handMadeBundle(t)
|
|
in.bundle, in.hosts, in.mirrorPath = dir, []string{"10.9.8.7"}, t.TempDir()
|
|
|
|
in.bundleSHA = ""
|
|
if err := in.checkBundle(); err == nil || !strings.Contains(err.Error(), "--bundle-sha256") {
|
|
t.Errorf("a bundle with no digest: %v", err)
|
|
}
|
|
in.bundleSHA = strings.Repeat("0", 64)
|
|
if err := in.checkBundle(); err == nil {
|
|
t.Error("a bundle not matching its digest was taken")
|
|
}
|
|
in.bundleSHA = digest
|
|
if err := in.run(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
if err := in.ensureBundle(context.Background()); err != nil {
|
|
t.Fatalf("%v\n%s", err, out)
|
|
}
|
|
|
|
cfg, err := config.Load(in.configPath())
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if cfg.Offline.Mirror != "http://10.9.8.7:8081" || cfg.ReleasesBase() != "http://10.9.8.7:8081/_llmgw/releases" {
|
|
t.Errorf("server.yaml: offline %+v, releases %s", cfg.Offline, cfg.ReleasesBase())
|
|
}
|
|
got := bundle.NewTrusted(cfg.Offline.ChecksumsFile()).For("llamacpp", "b1")
|
|
if len(got) != 1 {
|
|
t.Errorf("the control plane trusts %v", got)
|
|
}
|
|
if _, err := os.Stat(filepath.Join(in.mirrorPath, starterName, starterVersion, "qwen-q4_k_m.gguf")); err != nil {
|
|
t.Errorf("the starter model is not in the mirror: %v", err)
|
|
}
|
|
if !in.bundleCarries(starterName) || in.bundleCarries(guardModelName) {
|
|
t.Error("what the bundle carries was misread")
|
|
}
|
|
|
|
// Again, and nothing changes: not the mirror, not server.yaml.
|
|
before, _ := os.ReadFile(in.configPath())
|
|
if err := in.ensureBundle(context.Background()); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if after, _ := os.ReadFile(in.configPath()); string(after) != string(before) {
|
|
t.Error("init from the same bundle changed server.yaml again")
|
|
}
|
|
}
|