mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-10-08 14:36:38 +00:00
- Immich asks what runs its video and its recognition in one menu, in both modes, and gives the GPU to the server and to Machine learning; AMD uses ROCm - Frigate, Ollama, llama.cpp, Faster Whisper and Piper take the image built for the chosen GPU - The acceleration menu offers only what the host can run - An update or a recreation sends one notification with its result instead of the stop, backup and start of each container - A private bridge with nothing connected is not reported as down - Secondary containers of a stack appear in the App tab with their version and logo; Secure Gateway shows the same update state in both views - A mistyped value in the wizard asks the same question again
80 lines
3.5 KiB
Python
80 lines
3.5 KiB
Python
"""An application offers the acceleration profiles the host can run."""
|
|
|
|
from pathlib import Path
|
|
import sys
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
sys.path.insert(0, str(ROOT / "src"))
|
|
sys.path.insert(0, str(Path(__file__).resolve().parent))
|
|
|
|
from proxmenux_oci.catalog import Catalog
|
|
from proxmenux_oci.installer import DEFAULT_MODE, build_deployment
|
|
from test_advanced_flow_order import RecordingUI, storages
|
|
|
|
NODE = "/dev/dri/renderD128"
|
|
|
|
|
|
class OptionsUI(RecordingUI):
|
|
def __init__(self, answers=None):
|
|
super().__init__(answers)
|
|
self.options, self.messages = {}, []
|
|
|
|
def choose(self, text, options, default=None):
|
|
self.options[text] = [tag for tag, _ in options]
|
|
return super().choose(text, options, default)
|
|
|
|
def message(self, text, title=None):
|
|
self.messages.append(text)
|
|
|
|
|
|
@patch("proxmenux_oci.i18n.language", return_value="en")
|
|
@patch("proxmenux_oci.installer.host.storages", side_effect=storages)
|
|
@patch("proxmenux_oci.installer.host.bridges", return_value=[{"iface": "vmbr0", "cidr": "192.0.2.10/24"}])
|
|
@patch("proxmenux_oci.installer.host.timezone", return_value="Europe/Madrid")
|
|
class HostProfileTests(unittest.TestCase):
|
|
catalog = Catalog(ROOT)
|
|
|
|
def offered(self, app, gpus, kfd=False, answer=None):
|
|
template = self.catalog.compose(app)
|
|
prompt = template["proxmox"]["installer_profile"]["hardware_acceleration"]["prompt"]
|
|
ui = OptionsUI({prompt: answer} if answer else None)
|
|
with patch("proxmenux_oci.installer.host.gpus", return_value=gpus), \
|
|
patch("pathlib.Path.is_char_device", return_value=kfd):
|
|
plan = build_deployment(template, ui, DEFAULT_MODE)
|
|
return ui.options.get(prompt), ui, plan
|
|
|
|
def test_an_amd_host_is_not_offered_nvidia(self, *_):
|
|
amd = {"intel": [], "amd": [NODE], "nvidia": False}
|
|
self.assertEqual(self.offered("frigate", amd, kfd=True)[0], ["none", "vaapi", "rocm"])
|
|
self.assertEqual(self.offered("ollama", amd, kfd=True)[0], ["cpu", "rocm"])
|
|
self.assertEqual(self.offered("llamacpp", amd, kfd=True)[0], ["cpu", "rocm"])
|
|
|
|
def test_rocm_is_not_offered_without_its_compute_device(self, *_):
|
|
amd = {"intel": [], "amd": [NODE], "nvidia": False}
|
|
self.assertEqual(self.offered("frigate", amd, kfd=False)[0], ["none", "vaapi"])
|
|
|
|
def test_an_intel_and_nvidia_host_is_not_offered_amd(self, *_):
|
|
both = {"intel": [NODE], "amd": [], "nvidia": True}
|
|
self.assertEqual(self.offered("frigate", both)[0], ["none", "vaapi", "nvidia"])
|
|
self.assertEqual(self.offered("llamacpp", both)[0], ["cpu", "nvidia", "intel"])
|
|
|
|
def test_a_host_without_gpu_is_told_and_not_asked(self, *_):
|
|
nothing = {"intel": [], "amd": [], "nvidia": False}
|
|
for app in ("faster-whisper", "ollama", "frigate"):
|
|
options, ui, plan = self.offered(app, nothing)
|
|
self.assertIsNone(options, app)
|
|
self.assertTrue(any("No usable GPU" in message for message in ui.messages), app)
|
|
self.assertEqual(plan["devices"], [], app)
|
|
|
|
def test_the_render_node_proposed_belongs_to_the_gpu_of_the_profile(self, *_):
|
|
# The first render node of this host is the NVIDIA one; Intel's is the second.
|
|
gpus = {"intel": ["/dev/dri/renderD129"], "amd": [], "nvidia": True}
|
|
_, _, plan = self.offered("llamacpp", gpus, answer="intel")
|
|
self.assertEqual([device["host_path"] for device in plan["devices"]], ["/dev/dri/renderD129"])
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|