Repository navigation
Conversation
localai-org-maint-bot
left a comment
There was a problem hiding this comment.
[P1] Model admission checks the frontend filesystem even when inference runs on workers.
In core/gallery/backends.go:317-322 and core/gallery/models.go:676-683, backend availability is determined solely by ListSystemBackends(systemState). With the documented flag enabled on every frontend and worker, a normal distributed frontend with no local backend rejects a model whose vllm (or other) backend is already installed and runnable on a worker. Gallery admission returns 409; import/preload reaches the same local-only refusal in InstallModel. No backend download would have been needed.
NewDistributedModelManager explicitly disables local automatic backend installation because inference belongs to workers, but delegates model installation to LocalModelManager, so the new unconditional check still runs. Please make both admission and the lower-level model check aware of the execution target, while keeping actual backend installation disabled. Add a regression with an empty frontend backend directory and a compatible worker with the required backend already installed, plus a case with no eligible installed backend. This needs coordinated model-admission/worker handling rather than a minor formatting fix.
Reviewed against master 48f358dd9. After regenerating protobuf bindings locally, go test ./core/gallery -run Test -ginkgo.focus="Disabled backend installation" -count=1 -timeout=45s, go vet ./core/gallery, and diff whitespace checks pass. The distributed finding is from tracing the real call path; I did not run a live cluster. @mudler this blocks my sign-off on the advertised distributed configuration.
b3df98b to
6e6eda2
Compare
|
Thanks, indeed the model admission check read the frontend's own backend directory, which is empty in distributed mode, so every model install was refused there. What changed
Tests
Small "problem", left as is
|
6e6eda2 to
992ce88
Compare
…sition A hardening switch for deployments that must run exactly the backend set they were tested with (production, air-gapped, immutable images, package-managed hosts). With LOCALAI_DISABLE_BACKEND_INSTALL=1 every install and upgrade path refuses — gallery, OCI/URL/path, node-scoped, auto-upgrade, boot-time external backends — HTTP routes answer 403 up front, and a model whose backend is missing is refused before any download: 409 on the API, an error on preload and import. Whether a backend is present is asked of the execution target: the local backend directory on a single node, the workers' listings on a distributed frontend, which installs nothing itself. Backends already present, including system-path ones, keep working. Assisted-by: Claude Code:claude-fable-5 Signed-off-by: Plamen K. Kosseff <p.kosseff@gmail.com>
992ce88 to
6e1768c
Compare
Some deployments must not acquire executable code at runtime: production systems that run exactly the backend set they were tested with, air-gapped or locked-down hosts, immutable images, and hosts whose backends come from a package manager via
--backends-system-path. Today LocalAI will install a backend on its own in many situations — a gallery click, a model install, a model load on a worker, the background auto-upgrader — and nothing lets an operator forbid that.This adds
--disable-backend-install/LOCALAI_DISABLE_BACKEND_INSTALL(hardening group, off by default, not a runtime setting). With it on:gallery.InstallBackend,InstallBackendFromGalleryandUpgradeBackendreturn a typedErrBackendInstallDisabled, so every path ends in a refusal — gallery/OCI/URL/path installs, upgrades (manual, update-all, auto-upgrader), theLOCALAI_EXTERNAL_BACKENDSboot loop, the Assistant'sinstall_backend/upgrade_backend,local-ai backends upgrade. Backends already installed, system-path ones included, keep working: the "already present and runnable" short-circuit runs before the guard.409 {"code":"backend_not_installed","backend":…}up front; every other path (import, preload, the Assistant's tools) is refused insideInstallModelright after the config is validated — before any artifact or file is downloaded — with an error naming the backend. A model that names no backend passes, as the runtime picks one at load.403 {"code":"backend_install_disabled"}on the seven install/upgrade routes (/backends/apply,/backends/upgrade/:name,/api/backends/install/:id,/api/backends/install-external,/api/backends/upgrade/:name,/api/nodes/:id/backends/{install,upgrade}), so clients get an immediate answer instead of a failed job.SystemState, so install-on-load and frontend-requested installs/upgrades are refused where the bytes would land; the frontend'sDistributedBackendManagerrefuses fan-outs up front. The standalonelocal-ai worker …subcommands honour it too (they already prefer a present backend; a missing one now exits with the error instead of installing).backend_installinGET /api/featuresand the/.well-known/localai.jsoncapabilities; the Backends page shows a notice, keeps browsing and delete, and offers no install/upgrade/manual-install/check actions; the Import Model page states that the import will be refused instead of promising a download.Notes for Reviewers
The guard sits in three
core/galleryfunctions plus one pre-download check inInstallModel, rather than at each caller; the HTTP middleware exists only to give clients an immediate answer.When an install is refused, the op handler skips its "remove the half-installed directory" cleanup: nothing was written. That cleanup dates from feat(backends): add system backend, refactor #6059 (089efe0), when installs wrote directly into the backends path; since fix(gallery): make backend (re)install a clean replace instead of an overlay #10726 (1d5139f) installs stage into
<name>.install-tmpand swap atomically, so the cleanup now removes a working backend after any failed forced reinstall, not only a refused one — a separate fix.Swagger annotated (
@Failure 403/409) and regenerated; the 403/409 bodies use the flat{error, code}shapeconcreteFanOutGuardalready returns on/backends/apply.MCP: the in-process client refuses up front so the Assistant gets the error on the tool call; the
upgrade_backendskill and tool list say what to do on it.Tests: gallery (typed error, nothing written, present backend accepted, upgrade refused,
RequiredBackendInstalled, model refused before download, model accepted with its backend present), middleware (pass/403), UI routes through real registration (403 ×3, 409 naming the backend, pass-through for a backend-less entry), worker service (install and upgrade requests refused), worker CLI helper (present backend used, missing refused). Suites needing the PostgreSQL testcontainer weren't runnable in my environment (no Docker); their failure counts are unchanged by this change.Docs:
features/backends.md(new section),features/distributed-mode.md(worker note),reference/cli-reference.md(hardening row),features/api-discovery.md(capability).Out of scope, planned as a follow-up: marking gallery entries whose backend is missing on the Models page and disabling their Install button (the 409 covers the server side today). The
local-ai backends install/local-ai models installCLI subcommands remain deliberate operator actions.Yes, I signed my commits.
Documentation updated (docs/content/) for user-facing changes, or not applicable