feat(backend gallery): add meta packages

So we can have meta packages such as "vllm" that automatically installs
the corresponding package depending on the GPU that is being currently
detected in the system.

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
Ettore Di Giacinto 2025-06-20 19:16:53 +02:00
parent be3ff482d0
commit 9a34fc8c66
4 changed files with 346 additions and 13 deletions

View file

@ -5,8 +5,14 @@ import (
"path/filepath"
"github.com/mudler/LocalAI/core/config"
"github.com/mudler/LocalAI/core/system"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"gopkg.in/yaml.v2"
)
const (
testImage = "quay.io/mudler/tests:localai-backend-test"
)
var _ = Describe("Gallery Backends", func() {
@ -35,18 +41,203 @@ var _ = Describe("Gallery Backends", func() {
Describe("InstallBackendFromGallery", func() {
It("should return error when backend is not found", func() {
err := InstallBackendFromGallery(galleries, "non-existent", tempDir, nil)
err := InstallBackendFromGallery(galleries, nil, "non-existent", tempDir, nil)
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("no model found with name"))
Expect(err.Error()).To(ContainSubstring("no backend found with name \"non-existent\""))
})
It("should install backend from gallery", func() {
err := InstallBackendFromGallery(galleries, "test-backend", tempDir, nil)
err := InstallBackendFromGallery(galleries, nil, "test-backend", tempDir, nil)
Expect(err).ToNot(HaveOccurred())
Expect(filepath.Join(tempDir, "test-backend", "run.sh")).To(BeARegularFile())
})
})
Describe("Meta Backends", func() {
It("should identify meta backends correctly", func() {
metaBackend := &GalleryBackend{
Metadata: Metadata{
Name: "meta-backend",
},
CapabilitiesMap: map[string]string{
"nvidia": "nvidia-backend",
"amd": "amd-backend",
"intel": "intel-backend",
},
}
Expect(metaBackend.IsMeta()).To(BeTrue())
regularBackend := &GalleryBackend{
Metadata: Metadata{
Name: "regular-backend",
},
URI: testImage,
}
Expect(regularBackend.IsMeta()).To(BeFalse())
emptyMetaBackend := &GalleryBackend{
Metadata: Metadata{
Name: "empty-meta-backend",
},
CapabilitiesMap: map[string]string{},
}
Expect(emptyMetaBackend.IsMeta()).To(BeFalse())
nilMetaBackend := &GalleryBackend{
Metadata: Metadata{
Name: "nil-meta-backend",
},
CapabilitiesMap: nil,
}
Expect(nilMetaBackend.IsMeta()).To(BeFalse())
})
It("should find best backend from meta based on system capabilities", func() {
metaBackend := &GalleryBackend{
Metadata: Metadata{
Name: "meta-backend",
},
CapabilitiesMap: map[string]string{
"nvidia": "nvidia-backend",
"amd": "amd-backend",
"intel": "intel-backend",
},
}
nvidiaBackend := &GalleryBackend{
Metadata: Metadata{
Name: "nvidia-backend",
},
URI: testImage,
}
amdBackend := &GalleryBackend{
Metadata: Metadata{
Name: "amd-backend",
},
URI: testImage,
}
backends := GalleryElements[*GalleryBackend]{nvidiaBackend, amdBackend}
// Test with NVIDIA system state
nvidiaSystemState := &system.SystemState{GPUVendor: "nvidia"}
bestBackend := findBestBackendFromMeta(metaBackend, nvidiaSystemState, backends)
Expect(bestBackend).To(Equal(nvidiaBackend))
// Test with AMD system state
amdSystemState := &system.SystemState{GPUVendor: "amd"}
bestBackend = findBestBackendFromMeta(metaBackend, amdSystemState, backends)
Expect(bestBackend).To(Equal(amdBackend))
// Test with unsupported GPU vendor
unsupportedSystemState := &system.SystemState{GPUVendor: "unsupported"}
bestBackend = findBestBackendFromMeta(metaBackend, unsupportedSystemState, backends)
Expect(bestBackend).To(BeNil())
})
It("should handle meta backend deletion correctly", func() {
metaBackend := &GalleryBackend{
Metadata: Metadata{
Name: "meta-backend",
},
CapabilitiesMap: map[string]string{
"nvidia": "nvidia-backend",
"amd": "amd-backend",
"intel": "intel-backend",
},
}
nvidiaBackend := &GalleryBackend{
Metadata: Metadata{
Name: "nvidia-backend",
},
URI: testImage,
}
amdBackend := &GalleryBackend{
Metadata: Metadata{
Name: "amd-backend",
},
URI: testImage,
}
gallery := config.Gallery{
Name: "test-gallery",
URL: "file://" + filepath.Join(tempDir, "backend-gallery.yaml"),
}
galleryBackend := GalleryBackends{amdBackend, nvidiaBackend, metaBackend}
dat, err := yaml.Marshal(galleryBackend)
Expect(err).NotTo(HaveOccurred())
err = os.WriteFile(filepath.Join(tempDir, "backend-gallery.yaml"), dat, 0644)
Expect(err).NotTo(HaveOccurred())
// Test with NVIDIA system state
nvidiaSystemState := &system.SystemState{GPUVendor: "nvidia"}
err = InstallBackendFromGallery([]config.Gallery{gallery}, nvidiaSystemState, "meta-backend", tempDir, nil)
Expect(err).NotTo(HaveOccurred())
metaBackendPath := filepath.Join(tempDir, "meta-backend")
Expect(metaBackendPath).To(BeADirectory())
concreteBackendPath := filepath.Join(tempDir, "nvidia-backend")
Expect(concreteBackendPath).To(BeADirectory())
allBackends, err := ListSystemBackends(tempDir)
Expect(err).NotTo(HaveOccurred())
Expect(allBackends).To(HaveKey("meta-backend"))
Expect(allBackends).To(HaveKey("nvidia-backend"))
// Delete meta backend by name
err = DeleteBackendFromSystem(tempDir, "meta-backend")
Expect(err).NotTo(HaveOccurred())
// Verify meta backend directory is deleted
Expect(metaBackendPath).NotTo(BeADirectory())
// Verify concrete backend directory is deleted
Expect(concreteBackendPath).NotTo(BeADirectory())
})
It("should list meta backends correctly in system backends", func() {
// Create a meta backend directory with alias
metaBackendPath := filepath.Join(tempDir, "meta-backend")
err := os.MkdirAll(metaBackendPath, 0750)
Expect(err).NotTo(HaveOccurred())
// Create alias file pointing to concrete backend
aliasFilePath := filepath.Join(metaBackendPath, "meta")
err = os.WriteFile(aliasFilePath, []byte("concrete-backend"), 0644)
Expect(err).NotTo(HaveOccurred())
// Create the concrete backend directory with run.sh
concreteBackendPath := filepath.Join(tempDir, "concrete-backend")
err = os.MkdirAll(concreteBackendPath, 0750)
Expect(err).NotTo(HaveOccurred())
err = os.WriteFile(filepath.Join(concreteBackendPath, "run.sh"), []byte("#!/bin/bash"), 0755)
Expect(err).NotTo(HaveOccurred())
// List system backends
backends, err := ListSystemBackends(tempDir)
Expect(err).NotTo(HaveOccurred())
// Should include both the meta backend name and concrete backend name
Expect(backends).To(HaveKey("meta-backend"))
Expect(backends).To(HaveKey("concrete-backend"))
// meta-backend should point to its own run.sh
Expect(backends["meta-backend"]).To(Equal(filepath.Join(tempDir, "meta-backend", "run.sh")))
// concrete-backend should point to its own run.sh
Expect(backends["concrete-backend"]).To(Equal(filepath.Join(tempDir, "concrete-backend", "run.sh")))
})
})
Describe("InstallBackend", func() {
It("should create base path if it doesn't exist", func() {
newPath := filepath.Join(tempDir, "new-path")