Files
Ilker ManapandClaude Opus 5.5 bae16426a2 Offline sites and Kubernetes: llmgw bundle create, import and trust, offline.mirror, server init --bundle; a Helm chart for the control plane
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>
2026-10-05 00:13:39 +02:00

133 lines
3.8 KiB
Go

package bundle
import (
"bufio"
"bytes"
"errors"
"fmt"
"maps"
"os"
"path"
"path/filepath"
"slices"
"strings"
"sync"
"time"
)
// Trust records a bundle's engine checksums in the file the control plane
// reads them from, beside any recorded before, and says how many it holds
// now. Only the manifest is read: the checksums are what each node holds
// the files it fetches to, so the manifest must be the one that was made —
// which is what the digest says.
func Trust(p, file, digest string, unchecked bool) (Manifest, int, error) {
src, m, err := open(p)
if err != nil {
return Manifest{}, 0, err
}
defer src.close() //nolint:errcheck // read only
if err := checkDigest(src.manifest(), digest, unchecked); err != nil {
return m, 0, err
}
n, err := TrustManifest(m, file)
return m, n, err
}
// TrustManifest records a manifest's engine checksums, for one already
// checked by an import.
func TrustManifest(m Manifest, file string) (int, error) {
sums, err := readTrusted(file)
if err != nil && !errors.Is(err, os.ErrNotExist) {
return 0, err
}
if sums == nil {
sums = map[string]string{}
}
for _, f := range m.Files {
if strings.HasPrefix(f.Path, kindEngine+"/") {
sums[Prefix+"/"+f.Path] = f.SHA256
}
}
var b strings.Builder
b.WriteString("# Engine files the nodes may install, as the offline bundles they came in\n" +
"# gave them. Kept by 'llmgw bundle import' and 'llmgw bundle trust'.\n")
for _, k := range slices.Sorted(maps.Keys(sums)) {
fmt.Fprintf(&b, "%s %s\n", sums[k], k)
}
if err := os.MkdirAll(filepath.Dir(file), 0o755); err != nil {
return 0, err
}
tmp := file + partSuffix
if err := os.WriteFile(tmp, []byte(b.String()), 0o644); err != nil { //nolint:gosec // checksums, for anyone to read
return 0, err
}
return len(sums), os.Rename(tmp, file)
}
// readTrusted reads a checksums file: "<sha256> <path>" a line, as
// sha256sum writes them, with paths as the mirror has the files.
func readTrusted(file string) (map[string]string, error) {
b, err := os.ReadFile(file) //nolint:gosec // the control plane's own file
if err != nil {
return nil, err
}
out := map[string]string{}
sc := bufio.NewScanner(bytes.NewReader(b))
for sc.Scan() {
line := strings.TrimSpace(sc.Text())
if line == "" || strings.HasPrefix(line, "#") {
continue
}
f := strings.Fields(line)
if len(f) != 2 || len(f[0]) != 64 {
return nil, fmt.Errorf("%s: %q is not a checksum and a file", file, line)
}
out[strings.TrimPrefix(f[1], "*")] = f[0]
}
return out, sc.Err()
}
// Trusted is the engine checksums a control plane holds, read from their
// file again whenever it changes — so a bundle imported while the control
// plane runs is offered to the next node that asks.
type Trusted struct {
file string
mu sync.Mutex
mod time.Time
size int64
sums map[string]string
err error
}
// NewTrusted reads checksums from file as they are asked for.
func NewTrusted(file string) *Trusted { return &Trusted{file: file} }
// For is an engine version's files and their checksums, by file name; none
// when no bundle imported here carried it.
func (t *Trusted) For(engine, version string) map[string]string {
t.mu.Lock()
defer t.mu.Unlock()
if info, err := os.Stat(t.file); err != nil {
t.sums, t.err, t.mod, t.size = nil, err, time.Time{}, 0
} else if !info.ModTime().Equal(t.mod) || info.Size() != t.size {
t.sums, t.err = readTrusted(t.file)
t.mod, t.size = info.ModTime(), info.Size()
}
prefix := Prefix + "/" + kindEngine + "/" + engine + "/" + version + "/"
out := map[string]string{}
for p, sum := range t.sums {
if rest, ok := strings.CutPrefix(p, prefix); ok && path.Base(rest) == rest {
out[rest] = sum
}
}
return out
}
// Err is why the file could not be read, the last time it was.
func (t *Trusted) Err() error {
t.mu.Lock()
defer t.mu.Unlock()
return t.err
}