mirror of
https://github.com/MacRimi/ProxMenux.git
synced 2026-10-08 22:46:41 +00:00
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:
@@ -0,0 +1,62 @@
|
||||
"""Containers an OCI manager operation is working on.
|
||||
|
||||
An update or a recreation stops, backs up and starts its containers. The OCI
|
||||
engine marks them while it works and reports the result itself, so their
|
||||
stop, start and backup notices are part of the operation, not news.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import re
|
||||
import time
|
||||
|
||||
MARKERS = '/run/proxmenux/oci-operations'
|
||||
# The last start of an operation is noticed a little after it returned.
|
||||
GRACE_SECONDS = 180
|
||||
# A mark left behind by an operation that died is not trusted for ever.
|
||||
STALE_SECONDS = 6 * 3600
|
||||
QUIET_EVENTS = frozenset({
|
||||
'vm_start', 'vm_stop', 'vm_shutdown', 'vm_restart',
|
||||
'ct_start', 'ct_stop', 'ct_shutdown', 'ct_restart',
|
||||
'backup_start', 'backup_complete',
|
||||
})
|
||||
_OCI_BACKUP_PATH = '/proxmenux/oci/instances/'
|
||||
|
||||
|
||||
def active(vmid, now=None, root=MARKERS) -> bool:
|
||||
try:
|
||||
with open(os.path.join(root, str(int(vmid))), encoding='utf-8') as handle:
|
||||
mark = json.load(handle)
|
||||
started = float(mark.get('started') or 0)
|
||||
ended = mark.get('ended')
|
||||
except (OSError, ValueError, TypeError):
|
||||
return False
|
||||
now = time.time() if now is None else now
|
||||
if ended is None:
|
||||
return now - started < STALE_SECONDS
|
||||
return now - float(ended) < GRACE_SECONDS
|
||||
|
||||
|
||||
def _vmids(event) -> set:
|
||||
data = event.data or {}
|
||||
found = set()
|
||||
for value in (data.get('vmid'), getattr(event, 'entity_id', '')):
|
||||
if str(value or '').isdigit():
|
||||
found.add(int(value))
|
||||
if event.event_type.startswith('backup_'):
|
||||
text = ' '.join(str(data.get(key) or '') for key in ('reason', 'pve_message', 'vmname', 'guests'))
|
||||
found.update(int(value) for value in re.findall(r'\((\d{3,})\)|vzdump-(?:lxc|qemu)-(\d+)-', text)
|
||||
for value in value if value)
|
||||
return found
|
||||
|
||||
|
||||
def quiet(event, root=MARKERS) -> bool:
|
||||
"""Whether the event is a step of a running OCI operation."""
|
||||
if event.event_type not in QUIET_EVENTS or event.severity in ('CRITICAL', 'WARNING'):
|
||||
return False
|
||||
data = event.data or {}
|
||||
if event.event_type.startswith('backup_') and any(
|
||||
_OCI_BACKUP_PATH in str(data.get(key) or '') for key in ('reason', 'pve_message', 'filename')):
|
||||
# The working copy of an update lives in the OCI registry of the host.
|
||||
return True
|
||||
vmids = _vmids(event)
|
||||
return bool(vmids) and all(active(vmid, root=root) for vmid in vmids)
|
||||
Reference in New Issue
Block a user