feat(oci): GPU selection per host and per image, one notification per update, and App tab for stack containers

- 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
This commit is contained in:
MacRimi
2026-10-02 21:45:38 +02:00
parent 20ee21c08f
commit 9b5cefb81a
55 changed files with 2294 additions and 113 deletions
+26
View File
@@ -3158,6 +3158,20 @@ class HealthMonitor:
print(f"[HealthMonitor] Disk/IO check failed: {e}")
return {'status': 'UNKNOWN', 'reason': f'Disk check unavailable: {str(e)}', 'checks': {}, 'dismissable': True}
@staticmethod
def _bridge_is_idle(interface: str, root: str = '/sys/class/net') -> bool:
"""Whether a bridge is administratively up with no port attached.
Such a bridge reports no carrier, which is its normal state and not a
failure. A bridge that is set down, or one that has ports and still no
carrier, is not idle."""
try:
with open(f'{root}/{interface}/flags', encoding='ascii') as handle:
administratively_up = bool(int(handle.read().strip(), 16) & 0x1)
return administratively_up and not os.listdir(f'{root}/{interface}/brif')
except (OSError, ValueError):
return False
def _check_network_optimized(self) -> Dict[str, Any]:
"""
Optimized network check - only alerts for interfaces that are actually in use.
@@ -3206,6 +3220,18 @@ class HealthMonitor:
# Check if it's a bridge interface (always important for VMs/LXCs)
if interface.startswith('vmbr'):
if self._bridge_is_idle(interface):
# A bridge with no port attached has no carrier: the
# private network of an application whose containers
# are stopped, during an update for example. Nothing
# is down; nothing is connected to it.
interface_details[interface] = {
'status': 'OK',
'reason': 'Bridge without attached ports',
'is_up': False,
}
health_persistence.resolve_error(interface, 'Bridge without attached ports')
continue
should_alert = True
alert_reason = 'Bridge interface DOWN (VMs/LXCs may be affected)'