Files
llmgw/internal/web/admin_nodeengine.go
T
Ilker ManapandClaude Opus 5.5 52898fbb80 A V100 gets a ComfyUI it can run, and an open driver is read by its version
PyTorch's CUDA 12.8 and 12.9 builds start at Turing since torch 2.8, as
CUDA 13 does, so on a V100 both ComfyUI builds were installed, 10 GB each,
and failed on the card with "no kernel image". The cu129 build now needs
7.5, and a third, on PyTorch's CUDA 12.6 torch, carries Volta and Pascal.

The open kernel module, NVIDIA's default since 560, writes "Open Kernel
Module for x86_64  580.82.07" in /proc/driver/nvidia/version, and the word
after "Module" was taken as the driver: "for". With the driver unknown,
every build was tried whatever driver it needs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-13 10:21:27 +02:00

59 lines
2.2 KiB
Go

package web
import (
"context"
"net/http"
"net/url"
"gitea.mynodes.xyz/ilker/llmgw/internal/store"
)
// NodeEngineAdmin chooses an engine's build for a node: "auto", a build
// such as "cu129", or "none".
type NodeEngineAdmin interface {
SetNodeEngine(ctx context.Context, node, engine, build, by string) error
}
// RegisterNodeEngines mounts the choice of engine builds on the cluster
// page: for an administrator, with the session's CSRF token, and answered by
// going back to the page with what happened.
func (p *AccountPages) RegisterNodeEngines(mux *http.ServeMux, a NodeEngineAdmin) {
mux.HandleFunc("POST /admin/nodes/{id}/engines", p.adminOnly(func(w http.ResponseWriter, r *http.Request, admin store.User) {
sess, _, _ := p.session(r)
if !p.accounts.CheckCSRF(sess, r.FormValue("csrf")) {
http.Error(w, "bad request", http.StatusBadRequest)
return
}
node, engine, build := r.PathValue("id"), r.FormValue("engine"), r.FormValue("build")
q := url.Values{}
if err := a.SetNodeEngine(r.Context(), node, engine, build, admin.Email); err != nil {
p.log.Warn("an engine build was not chosen", "admin", admin.Email, "node", node, "err", err)
// The control plane's reason, as it gave it: in English.
q.Set("problem", node+": "+err.Error())
} else {
p.log.Info("an engine build was chosen", "admin", admin.Email, "node", node, "engine", engine, "build", build)
// Said in the language of the person who chose, since the
// sentence travels to the page in the address.
q.Set("notice", buildNotice(langOf(r), node, engine, build))
}
http.Redirect(w, r, "/admin?"+q.Encode(), http.StatusSeeOther)
}))
}
// buildNotice says what a node was told to install. A whole sentence for
// each kind of choice, because where the build goes in it is the
// language's business.
func buildNotice(l *Lang, node, engine, build string) string {
switch build {
case "auto":
return l.T("nodeengine.notice.auto", node, engine)
case "none":
return l.T("nodeengine.notice.none", node, engine)
}
name := map[string]string{"cu13": "CUDA 13", "cu129": "CUDA 12.9", "cu126": "CUDA 12.6", "cu12": "CUDA 12"}[build]
if name == "" {
name = build
}
return l.T("nodeengine.notice.build", node, engine, name)
}