The mirror holds the weights, so the mirror does the downloading. A control plane that had to pull the bytes itself and push them here would carry every model twice over the network, through the one machine least able to spare the bandwidth. Two listeners, and the split is the point. Weights stay on plain HTTP where every node can reach them: that path is eight nodes pulling forty gigabytes, and putting a client certificate in front of it would mean re-certifying every agent's fetcher in order to change how models are administered. Management gets its own port, which can be given the fleet's CA — the same tlsconf the agent stream uses, so this is a configuration rather than a new idea. A fetch answers 202, not 200. The bytes are not here yet, and a caller that read it as "done" would point a catalog at a file still arriving, which every node would then copy. Progress is asked for rather than waited on, because no client between here and the operator will hold a connection open for an hour. A failed fetch is remembered with its reason. Forgetting it would leave the control plane waiting on a model that is never coming, with nothing to say why. Status falls back to reading the disk, so a restart does not report a model that is plainly there as unknown. Removal takes the whole version: a model split across files is useless with one of them missing, and half a version on disk looks present and will not load. It refuses while a download is running, because the fetch would carry on writing and the file would reappear, looking like the delete had silently failed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
47 lines
1.5 KiB
Go
47 lines
1.5 KiB
Go
package cli
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/mirror"
|
|
)
|
|
|
|
func TestTheMirrorRefusesEverythingButReads(t *testing.T) {
|
|
// Stated here rather than inherited from http.FileServer, so a handler
|
|
// added later cannot quietly make the mirror writable — which would turn
|
|
// it into a way to replace a model with another one that every node then
|
|
// fetches without complaint.
|
|
h := readOnly(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
|
|
w.WriteHeader(http.StatusOK)
|
|
}))
|
|
|
|
for _, m := range []string{http.MethodGet, http.MethodHead} {
|
|
rec := httptest.NewRecorder()
|
|
h.ServeHTTP(rec, httptest.NewRequest(m, "/x.gguf", nil))
|
|
if rec.Code != http.StatusOK {
|
|
t.Errorf("%s was refused: %d", m, rec.Code)
|
|
}
|
|
}
|
|
for _, m := range []string{http.MethodPut, http.MethodPost, http.MethodDelete, http.MethodPatch} {
|
|
rec := httptest.NewRecorder()
|
|
h.ServeHTTP(rec, httptest.NewRequest(m, "/x.gguf", nil))
|
|
if rec.Code != http.StatusMethodNotAllowed {
|
|
t.Errorf("%s was allowed: %d", m, rec.Code)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestTheFilenameIsTakenFromTheURLWhenNotGiven(t *testing.T) {
|
|
for _, c := range []struct{ url, want string }{
|
|
{"https://h/a/b/model.gguf", "model.gguf"},
|
|
{"https://h/model.gguf?download=true", "model.gguf"},
|
|
{"model.gguf", "model.gguf"},
|
|
} {
|
|
if got := mirror.LastPathElement(c.url); got != c.want {
|
|
t.Errorf("mirror.LastPathElement(%q) = %q, want %q", c.url, got, c.want)
|
|
}
|
|
}
|
|
}
|