Files
LocalAI/pkg/system/state.go
T
Plamen K. Kosseff 104c2fb440 fix(oci): stage image downloads in a configured directory, not in /tmp (#12280)
* fix(oci): stage image downloads in a configured directory, not in /tmp

Problem:
- the image tar and its compressed layers staged in os.TempDir()
- /tmp is commonly a RAM-backed tmpfs far smaller than a backend image
- big installs failed with a full /tmp or silently ate RAM

Change:
- staging path resolved like the other storage paths
  (LOCALAI_DOWNLOAD_STAGING_PATH, default ${basepath}/downloading),
  threaded to the extractor as a download option
- every download works in its own subdirectory holding its tar and
  layers: nothing shared between concurrent downloads, one removal
  cleans a download up, a crash leaves one self-contained orphan
- callers that pass no staging directory keep the OS temp behavior

Assisted-by: Claude:claude-fable-5
Signed-off-by: Plamen K. Kosseff <p.kosseff@gmail.com>

* fix(oci): handle staging cleanup errors

Log staging cleanup failures to satisfy errcheck. Test extraction with an
unavailable OS temp directory and verify that staging is removed.

Assisted-by: Codex:GPT-6
Signed-off-by: Plamen K. Kosseff <p.kosseff@gmail.com>

---------

Signed-off-by: Plamen K. Kosseff <p.kosseff@gmail.com>
2026-10-05 01:27:45 +02:00

117 lines
2.9 KiB
Go

package system
import (
"github.com/mudler/LocalAI/pkg/xsysinfo"
"github.com/mudler/xlog"
)
type Backend struct {
BackendsPath string
BackendsSystemPath string
}
type Model struct {
ModelsPath string
}
type SystemState struct {
GPUVendor string
Backend Backend
Model Model
VRAM uint64
// StagingPath holds in-flight downloads before extraction; empty
// falls back to the OS temp directory.
StagingPath string
systemCapabilities string
// Backend image fallback tag configuration
BackendImagesReleaseTag string
BackendImagesBranchTag string
BackendDevSuffix string
// PreferDevelopmentBackends installs the development image as the primary
// backend URI (the released image becomes a fallback) rather than only using
// development as a download fallback when the released image is missing.
PreferDevelopmentBackends bool
// RequireBackendIntegrity is the strict-integrity switch bound to
// --require-backend-integrity / LOCALAI_REQUIRE_BACKEND_INTEGRITY. The
// backend install path takes it as a call argument; the gallery index
// fetch reads it from here because the listing code it runs under never
// sees the application config.
RequireBackendIntegrity bool
}
type SystemStateOptions func(*SystemState)
func WithBackendPath(path string) SystemStateOptions {
return func(s *SystemState) {
s.Backend.BackendsPath = path
}
}
func WithBackendSystemPath(path string) SystemStateOptions {
return func(s *SystemState) {
s.Backend.BackendsSystemPath = path
}
}
func WithStagingPath(path string) SystemStateOptions {
return func(s *SystemState) {
s.StagingPath = path
}
}
func WithModelPath(path string) SystemStateOptions {
return func(s *SystemState) {
s.Model.ModelsPath = path
}
}
func WithBackendImagesReleaseTag(tag string) SystemStateOptions {
return func(s *SystemState) {
s.BackendImagesReleaseTag = tag
}
}
func WithBackendImagesBranchTag(tag string) SystemStateOptions {
return func(s *SystemState) {
s.BackendImagesBranchTag = tag
}
}
func WithBackendDevSuffix(suffix string) SystemStateOptions {
return func(s *SystemState) {
s.BackendDevSuffix = suffix
}
}
func WithRequireBackendIntegrity(require bool) SystemStateOptions {
return func(s *SystemState) {
s.RequireBackendIntegrity = require
}
}
func WithPreferDevelopmentBackends(prefer bool) SystemStateOptions {
return func(s *SystemState) {
s.PreferDevelopmentBackends = prefer
}
}
func GetSystemState(opts ...SystemStateOptions) (*SystemState, error) {
state := &SystemState{}
for _, opt := range opts {
opt(state)
}
// Detection is best-effort here, we don't want to fail if it fails
state.GPUVendor, _ = xsysinfo.DetectGPUVendor()
xlog.Debug("GPU vendor", "gpuVendor", state.GPUVendor)
state.VRAM, _ = xsysinfo.TotalAvailableVRAM()
xlog.Debug("Total available VRAM", "vram", state.VRAM)
state.getSystemCapabilities()
return state, nil
}