From f3c4959fa4f2166b55a152ed1670e3f3a2b51bd5 Mon Sep 17 00:00:00 2001 From: MacRimi Date: Sun, 27 Sep 2026 21:02:16 +0200 Subject: [PATCH] OCI catalog verification, console start marks and log cleanup --- AppImage/components/oci-console-log-panel.tsx | 52 ++++++-- AppImage/messages/de/common.json | 3 + AppImage/messages/en/common.json | 3 + AppImage/messages/es/common.json | 3 + AppImage/messages/fr/common.json | 3 + AppImage/messages/it/common.json | 3 + AppImage/messages/pt/common.json | 3 + AppImage/messages/sk/common.json | 3 + AppImage/messages/sv/common.json | 3 + AppImage/scripts/flask_server.py | 38 +++++- AppImage/scripts/oci_console_logs.py | 20 ++- lang/de.json | 1 + lang/es.json | 1 + lang/fr.json | 1 + lang/it.json | 1 + lang/pt.json | 1 + lang/sk.json | 1 + lang/sv.json | 1 + oci/README.md | 6 + oci/catalog/apps/glances.json | 4 + oci/catalog/apps/pocketbase.json | 4 + oci/catalog/index.json | 8 ++ oci/catalog/verification.json | 125 ++++++++++++++++++ oci/remote/oci_console.py | 24 +++- oci/remote/oci_console_mark.sh | 9 ++ oci/remote/oci_instance_transaction.py | 4 +- oci/remote/oci_remove.py | 3 + oci/schemas/oci-template.schema.json | 9 ++ oci/src/proxmenux_oci/catalog.py | 29 ++++ oci/src/proxmenux_oci/cli.py | 9 +- web/messages/en/docs/oci-manager/index.json | 3 + web/messages/en/docs/oci-manager/monitor.json | 2 + web/messages/es/docs/oci-manager/index.json | 3 + web/messages/es/docs/oci-manager/monitor.json | 2 + 34 files changed, 365 insertions(+), 20 deletions(-) create mode 100644 oci/catalog/verification.json create mode 100755 oci/remote/oci_console_mark.sh diff --git a/AppImage/components/oci-console-log-panel.tsx b/AppImage/components/oci-console-log-panel.tsx index f37eaf9f..68eb01f7 100644 --- a/AppImage/components/oci-console-log-panel.tsx +++ b/AppImage/components/oci-console-log-panel.tsx @@ -24,12 +24,20 @@ interface ConsoleLogResponse { inode: number | null reset?: boolean head_truncated?: boolean + start_marks?: boolean error?: string } const LINE_OPTIONS = [100, 500, 1000] as const const POLL_MS = 2000 +// Written into the log by the container's pre-start hook at every start. +const START_MARK_RE = /^=== ProxMenux: container started (\d{4}-\d{2}-\d{2}) (\d{2}:\d{2}:\d{2}) ===$/ +const lastStart = (lines: string[]) => { + for (let i = lines.length - 1; i >= 0; i--) if (START_MARK_RE.test(lines[i])) return i + return -1 +} + const lineTone = (line: string) => { if (/\b(error|fatal|panic|critical|exception)\b/i.test(line)) return "text-red-400" if (/\bwarn(ing)?\b/i.test(line)) return "text-amber-400" @@ -45,6 +53,7 @@ export function OciConsoleLogPanel({ vmid, running }: { vmid: number; running: b const [error, setError] = useState(null) const [follow, setFollow] = useState(true) const [filter, setFilter] = useState("") + const [sinceStart, setSinceStart] = useState(true) const position = useRef<{ offset: number; inode: number | null } | null>(null) const scroller = useRef(null) const inFlight = useRef(false) @@ -53,7 +62,9 @@ export function OciConsoleLogPanel({ vmid, running }: { vmid: number; running: b setLoading(true) setError(null) try { - const r = await fetchApi(`/api/lxc/${vmid}/console-log?lines=${lineCount}`) + const r = await fetchApi( + `/api/lxc/${vmid}/console-log?lines=${lineCount}${sinceStart ? "&since_start=1" : ""}`, + ) setEnabled(r.enabled) setLines(r.lines || []) position.current = { offset: r.offset, inode: r.inode } @@ -63,7 +74,7 @@ export function OciConsoleLogPanel({ vmid, running }: { vmid: number; running: b } finally { setLoading(false) } - }, [vmid, lineCount]) + }, [vmid, lineCount, sinceStart]) const poll = useCallback(async () => { const pos = position.current @@ -79,7 +90,10 @@ export function OciConsoleLogPanel({ vmid, running }: { vmid: number; running: b setLines(r.lines || []) } else if (r.lines?.length) { setLines((prev) => { - const next = prev.concat(r.lines) + let next = prev.concat(r.lines) + // A restart while following opens a new session. + const mark = sinceStart ? lastStart(next) : -1 + if (mark > 0) next = next.slice(mark) return next.length > lineCount ? next.slice(next.length - lineCount) : next }) } @@ -88,7 +102,7 @@ export function OciConsoleLogPanel({ vmid, running }: { vmid: number; running: b } finally { inFlight.current = false } - }, [vmid, lineCount]) + }, [vmid, lineCount, sinceStart]) useEffect(() => { load() @@ -105,7 +119,7 @@ export function OciConsoleLogPanel({ vmid, running }: { vmid: number; running: b const shown = useMemo(() => { const needle = filter.trim().toLowerCase() - return needle ? lines.filter((l) => l.toLowerCase().includes(needle)) : lines + return needle ? lines.filter((l) => START_MARK_RE.test(l) || l.toLowerCase().includes(needle)) : lines }, [lines, filter]) useEffect(() => { @@ -145,6 +159,15 @@ export function OciConsoleLogPanel({ vmid, running }: { vmid: number; running: b {enabled && (
+