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>
59 lines
2.2 KiB
Go
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)
|
|
}
|