Update 1.2.2.1 beta

This commit is contained in:
MacRimi
2026-06-05 19:22:07 +02:00
parent 9656b04a3e
commit 3191f5250d
14 changed files with 892 additions and 26 deletions

View File

@@ -31,6 +31,7 @@ export default async function SystemOverviewTabPage({
const messages = (await getMessages({ locale })) as unknown as {
docs: { monitor: { dashboard: { systemOverview: {
topRow: { rows: TopRow[]; thresholdsItems: string[] }
processes: { listItems: string[]; detailItems: string[] }
bottom: { storageItems: string[] }
refresh: { items: string[] }
dataCollected: { rows: DataRow[] }
@@ -40,6 +41,8 @@ export default async function SystemOverviewTabPage({
const so = messages.docs.monitor.dashboard.systemOverview
const topRows = so.topRow.rows
const thresholdsItems = so.topRow.thresholdsItems
const processListItems = so.processes.listItems
const processDetailItems = so.processes.detailItems
const storageItems = so.bottom.storageItems
const refreshItems = so.refresh.items
const dataRows = so.dataCollected.rows
@@ -135,6 +138,58 @@ export default async function SystemOverviewTabPage({
{t("topRow.sparklineBody")}
</Callout>
<h2 className="text-2xl font-semibold mt-10 mb-4 text-gray-900">{t("processes.heading")}</h2>
<p className="mb-4 text-gray-800 leading-relaxed">
{t.rich("processes.intro", { code })}
</p>
<h3 className="text-lg font-semibold mt-6 mb-2 text-gray-900">{t("processes.listTitle")}</h3>
<ul className="list-disc pl-6 mb-4 text-gray-800 leading-relaxed space-y-1">
{processListItems.map((_, idx) => (
<li key={idx}>{t.rich(`processes.listItems.${idx}`, { strong })}</li>
))}
</ul>
<figure className="my-6">
<img
src="/monitor/system-overview-top-processes.png"
alt={t("processes.captureListAlt")}
className="rounded-lg border border-gray-200 shadow-sm w-full"
/>
<figcaption className="text-sm text-gray-500 mt-2 text-center italic">
{t("processes.captureListCaption")}
</figcaption>
</figure>
<h3 className="text-lg font-semibold mt-6 mb-2 text-gray-900">{t("processes.detailTitle")}</h3>
<p className="mb-4 text-gray-800 leading-relaxed">
{t.rich("processes.detailIntro", { code })}
</p>
<ul className="list-disc pl-6 mb-4 text-gray-800 leading-relaxed space-y-1">
{processDetailItems.map((_, idx) => (
<li key={idx}>{t.rich(`processes.detailItems.${idx}`, { strong, code })}</li>
))}
</ul>
<p className="mb-4 text-gray-800 leading-relaxed">
{t.rich("processes.detailRefresh", { em, code })}
</p>
<figure className="my-6">
<img
src="/monitor/system-overview-process-detail.png"
alt={t("processes.captureDetailAlt")}
className="rounded-lg border border-gray-200 shadow-sm w-full"
/>
<figcaption className="text-sm text-gray-500 mt-2 text-center italic">
{t("processes.captureDetailCaption")}
</figcaption>
</figure>
<h3 className="text-lg font-semibold mt-6 mb-2 text-gray-900">{t("processes.sourceTitle")}</h3>
<p className="mb-6 text-gray-800 leading-relaxed">
{t.rich("processes.sourceBody", { code, em })}
</p>
<h2 className="text-2xl font-semibold mt-10 mb-4 text-gray-900">{t("middle.heading")}</h2>
<p className="mb-4 text-gray-800 leading-relaxed">
{t.rich("middle.body1", { code, em })}

View File

@@ -20,7 +20,7 @@
"title": "Before you start",
"drivers": "<strong>Coral drivers already installed on the host</strong>. This script does not install them; it only configures passthrough to the container. Run <hostLink>Install Coral TPU on the Host</hostLink> first if you haven't.",
"driversCheck": "ls /dev/apex_* 2>/dev/null ; lsusb | grep -E '1a6e:089a|18d1:9302'",
"container": "<strong>An existing LXC container</strong>, ideally running a <strong>Debian / Ubuntu</strong>-based distro. The inside-container install uses <code>apt-get</code>; Alpine / Arch containers are not currently supported by this script.",
"container": "<strong>An existing LXC container</strong>, ideally running a <strong>Debian / Ubuntu</strong>-based distro — the in-container runtime install uses <code>apt-get</code>. <strong>Non-Debian containers</strong> (Alpine, Arch, RHEL, SUSE…) are still supported in <strong>passthrough-only mode</strong>: the script detects the distro and offers a prompt to skip the <code>libedgetpu</code> APT install while still writing the device passthrough config — useful for app containers that bundle the runtime themselves (e.g. the Frigate Docker image).",
"downtime": "<strong>Be OK with a brief downtime</strong> of the container. The script stops it to apply config changes, then starts it back up to install drivers inside. No host reboot needed."
},
"hostPrep": {
@@ -70,8 +70,8 @@
],
"noIgpuTitle": "Why no iGPU drivers here?",
"noIgpuBody": "Earlier versions of this script also installed Intel <code>va-driver-all</code>, <code>intel-opencl-icd</code> and friends so the same container could do Quick Sync video decode alongside Coral inference. That doubled-up responsibility caused confusing failures when the user only wanted Coral. The iGPU side is now the exclusive job of <lxcGpuLink>Add GPU to LXC</lxcGpuLink> — run it first if you also want hardware video decode in the container.",
"debianTitle": "Debian / Ubuntu containers only",
"debianBody": "The in-container install uses <code>apt-get</code> directly. Alpine, Arch or RHEL-based containers are not currently supported — the install step will fail and leave the LXC with the passthrough config but no drivers inside. For those distros, install the Coral runtime manually following Google's <coralLink>official guide</coralLink> after the LXC config step."
"debianTitle": "Non-Debian containers — passthrough-only mode",
"debianBody": "The in-container runtime install uses <code>apt-get</code>, which only ships on Debian/Ubuntu-family distros. On <strong>Alpine, Arch, RHEL or SUSE</strong> containers the script detects the distro via <code>/etc/os-release</code> and shows a confirmation prompt: <em>continue in passthrough-only mode</em> (writes the device config to <code>/etc/pve/lxc/&lt;ctid&gt;.conf</code> and skips the <code>libedgetpu</code> APT install) or <em>abort</em>. Passthrough-only is the right choice if the app container that will actually use Coral already bundles the runtime — the canonical example is the Frigate Docker image. Otherwise, follow Google's <coralLink>official guide</coralLink> to install <code>libedgetpu</code> manually after the script has written the LXC config."
},
"summary": {
"title": "Summary",
@@ -95,8 +95,8 @@
"apexBody": "Host apex module isn't loaded. On the host: <code>lsmod | grep apex</code> — if empty, run <code>modprobe apex</code>, or reboot if you just installed Coral drivers. Once the host has <code>/dev/apex_0</code>, restart the container: <code>pct stop &lt;ctid&gt; &amp;&amp; pct start &lt;ctid&gt;</code>.",
"replugTitle": "USB Coral disappears after replug in a different port",
"replugBody": "This is exactly why the script mounts <code>/dev/bus/usb</code> instead of the <code>/dev/coral</code> symlink. If you're hitting this, check your LXC config has <code>lxc.mount.entry: /dev/bus/usb dev/bus/usb ...</code> and not a reference to <code>/dev/coral</code> directly. Old configs from earlier script versions may need updating — re-run the script on the same container and the config gets refreshed.",
"alpineTitle": "In-container install fails on an Alpine container",
"alpineBody": "The script uses <code>apt-get</code>, which Alpine doesn't have. The LXC passthrough config is still valid — just install the Coral runtime manually with <code>apk add</code> following Google's guide for Alpine, or use a Debian-based container if you don't need the smaller footprint.",
"alpineTitle": "Alpine / Arch / RHEL / SUSE container — runtime not installed",
"alpineBody": "If you chose <em>passthrough-only mode</em> when the script prompted, the LXC config is written and the Coral device is visible inside the container, but the <code>libedgetpu</code> runtime is not installed. That's by design: Google's APT repo only ships for Debian/Ubuntu. Install the runtime manually with your distro's package manager (Alpine: <code>apk add</code>; Arch: AUR; RHEL/SUSE: build from source) following Google's official guide, or run an app container that bundles the runtime — the Frigate Docker image is the canonical example: just expose the device with <code>--device /dev/apex_0:/dev/apex_0</code> (M.2) or the USB bind mount the script already wrote (USB).",
"frigateTitle": "Frigate says 'Coral EdgeTPU detected but not available'",
"frigateBody": "Almost always a permissions issue inside the container. Frigate runs as root by default; check the root user is in the <code>plugdev</code> group inside the container (for USB), and that the process can read <code>/dev/apex_0</code> (for M.2). <code>ls -l /dev/apex_0</code> from inside the container should show group <code>apex</code> — if not, add the GID alignment to <code>/etc/group</code> or switch the container to privileged mode.",
"logsTitle": "Check both host and container logs",

View File

@@ -53,6 +53,32 @@
"sparklineTitle": "The sparkline is meaningful",
"sparklineBody": "The temperature card draws a 5-minute trace under the value, with the line and gradient colour following the same Warning/Critical pair documented above. It's the fastest way to see whether the host is in a thermal climb without opening the detail modal."
},
"processes": {
"heading": "Click-through: top processes by CPU / Memory",
"intro": "The CPU Usage and Memory cards are clickable. Clicking either opens a sortable list of the top 25 processes — the CPU card sorts by <code>%CPU</code>, the Memory card sorts by resident memory (RSS). Both pull from <code>/api/processes?sort=cpu|mem&limit=25</code>, which runs a single <code>ps -eo pid,user,pcpu,pmem,rss,comm</code> per refresh.",
"listTitle": "The list modal",
"listItems": [
"<strong>Auto-refresh</strong> — the list re-fetches every 5 s while the dialog is open. Closing the dialog stops all polling.",
"<strong>Filter box</strong> — matches against command, user or PID without re-fetching from the server.",
"<strong>Inline progress bar</strong> — the primary metric column draws a bar scaled to the largest value in the filtered list, so visual ranking is preserved even when no process is near 100 %.",
"<strong>Mobile layout</strong> — under 640 px the PID and User columns drop out so Command, CPU % and Memory still fit without horizontal scroll."
],
"captureListAlt": "Top processes by Memory modal — table with PID, USER, COMMAND, CPU %, Memory columns sorted by RSS",
"captureListCaption": "The Memory card opens the list sorted by RSS (indigo accent). The CPU card opens the same list sorted by %CPU (blue accent).",
"detailTitle": "Per-process detail",
"detailIntro": "Clicking any row in the list opens a second modal with the full live picture of that one process, served from <code>/api/processes/&lt;pid&gt;</code>. Four sections:",
"detailItems": [
"<strong>Overview</strong> — state (<code>R</code>/<code>S</code>/<code>D</code>/<code>Z</code>/…), parent (<code>PPid</code> + parent <code>comm</code>), thread count, open FD count, user and group.",
"<strong>Resources</strong> — CPU %, Memory %, Resident (RSS), Virtual size, Swap, I/O read and write bytes.",
"<strong>Command</strong> — short name (<code>comm</code>), full command line, executable path and working directory.",
"<strong>Lifetime</strong> — start timestamp and elapsed runtime."
],
"detailRefresh": "The detail modal refreshes every 3 s while open. If the process exits mid-modal the next refresh surfaces <em>Process exited</em> instead of stale data — expected for short-lived helpers like <code>pct exec</code> or backup subprocesses.",
"captureDetailAlt": "Process detail modal — Overview, Resources, Command and Lifetime sections for a single PID",
"captureDetailCaption": "Per-process detail modal opened from a list row. The accent colour matches the card that opened it (blue for CPU, indigo for Memory).",
"sourceTitle": "Where the data comes from",
"sourceBody": "<code>/api/processes/&lt;pid&gt;</code> reads <code>/proc/&lt;pid&gt;/cmdline</code>, <code>/exe</code>, <code>/cwd</code>, <code>/status</code>, <code>/io</code> and <code>/fd</code> directly, and calls <code>ps -o lstart=,etime=,pcpu=,pmem= -p &lt;pid&gt;</code> for the live fields the kernel doesn't expose in <code>/proc</code>. UID and GID are resolved to user / group names through Python's <code>pwd</code> / <code>grp</code> modules. Both endpoints are pure on-demand HTTP handlers — no daemon, no background sampling. Nothing runs on the server when the modal is closed."
},
"middle": {
"heading": "Middle: node metrics charts",
"body1": "Below the top row sits the <code>NodeMetricsCharts</code> component — historical CPU, memory and disk-I/O graphs sourced from Proxmox's own RRD store via <code>/api/node/metrics</code>. A timeframe selector switches between <em>1 hour / 24 hours / 7 days / 30 days / 1 year</em>; data resolution drops as the window grows so the chart stays smooth.",

View File

@@ -20,7 +20,7 @@
"title": "Antes de empezar",
"drivers": "<strong>Drivers de Coral ya instalados en el host</strong>. Este script no los instala; solo configura el passthrough al contenedor. Ejecuta <hostLink>Install Coral TPU on the Host</hostLink> primero si no lo has hecho.",
"driversCheck": "ls /dev/apex_* 2>/dev/null ; lsusb | grep -E '1a6e:089a|18d1:9302'",
"container": "<strong>Un contenedor LXC existente</strong>, idealmente con una distro basada en <strong>Debian / Ubuntu</strong>. La instalación dentro del contenedor usa <code>apt-get</code>; los contenedores Alpine / Arch no están soportados por este script actualmente.",
"container": "<strong>Un contenedor LXC existente</strong>, idealmente con una distro basada en <strong>Debian / Ubuntu</strong> — la instalación del runtime dentro del contenedor usa <code>apt-get</code>. Los <strong>contenedores no-Debian</strong> (Alpine, Arch, RHEL, SUSE…) siguen estando soportados en <strong>modo passthrough-only</strong>: el script detecta la distro y ofrece un prompt para saltarse la instalación APT de <code>libedgetpu</code> mientras escribe la config de passthrough del dispositivo — útil para contenedores de aplicación que ya incluyen el runtime (p.ej. la imagen Docker de Frigate).",
"downtime": "<strong>Asume una breve interrupción</strong> del contenedor. El script lo para para aplicar los cambios de config y lo arranca de nuevo para instalar los drivers dentro. No hace falta reiniciar el host."
},
"hostPrep": {
@@ -70,8 +70,8 @@
],
"noIgpuTitle": "¿Por qué no hay drivers de iGPU aquí?",
"noIgpuBody": "Versiones anteriores de este script también instalaban Intel <code>va-driver-all</code>, <code>intel-opencl-icd</code> y compañía para que el mismo contenedor pudiera hacer decode de vídeo Quick Sync junto a la inferencia de Coral. Esa doble responsabilidad causaba fallos confusos cuando el usuario solo quería Coral. El lado iGPU es ahora trabajo exclusivo de <lxcGpuLink>Añadir GPU a LXC</lxcGpuLink> — ejecútalo primero si también quieres decode de vídeo por hardware en el contenedor.",
"debianTitle": "Solo contenedores Debian / Ubuntu",
"debianBody": "La instalación dentro del contenedor usa <code>apt-get</code> directamente. Los contenedores Alpine, Arch o basados en RHEL no están soportados actualmente — el paso de instalación fallará y dejará el LXC con la config de passthrough pero sin drivers dentro. Para esas distros, instala el runtime de Coral manualmente siguiendo la <coralLink>guía oficial</coralLink> de Google después del paso de config del LXC."
"debianTitle": "Contenedores no-Debian — modo passthrough-only",
"debianBody": "La instalación del runtime dentro del contenedor usa <code>apt-get</code>, que solo viene con distros de la familia Debian/Ubuntu. En contenedores <strong>Alpine, Arch, RHEL o SUSE</strong> el script detecta la distro vía <code>/etc/os-release</code> y muestra un prompt de confirmación: <em>continuar en modo passthrough-only</em> (escribe la config del dispositivo en <code>/etc/pve/lxc/&lt;ctid&gt;.conf</code> y se salta la instalación APT de <code>libedgetpu</code>) o <em>cancelar</em>. Passthrough-only es la opción correcta si el contenedor de aplicación que va a usar Coral ya incluye el runtime — el ejemplo canónico es la imagen Docker de Frigate. Si no, sigue la <coralLink>guía oficial</coralLink> de Google para instalar <code>libedgetpu</code> manualmente después de que el script haya escrito la config del LXC."
},
"summary": {
"title": "Resumen",
@@ -95,8 +95,8 @@
"apexBody": "El módulo apex del host no está cargado. En el host: <code>lsmod | grep apex</code> — si está vacío, ejecuta <code>modprobe apex</code>, o reinicia si acabas de instalar los drivers de Coral. Una vez el host tenga <code>/dev/apex_0</code>, reinicia el contenedor: <code>pct stop &lt;ctid&gt; &amp;&amp; pct start &lt;ctid&gt;</code>.",
"replugTitle": "La Coral USB desaparece al reconectarla en otro puerto",
"replugBody": "Justo por eso el script monta <code>/dev/bus/usb</code> en lugar del symlink <code>/dev/coral</code>. Si te pasa esto, comprueba que tu config del LXC tiene <code>lxc.mount.entry: /dev/bus/usb dev/bus/usb ...</code> y no una referencia directa a <code>/dev/coral</code>. Las configs viejas de versiones anteriores del script pueden necesitar actualizarse — vuelve a ejecutar el script sobre el mismo contenedor y la config se refresca.",
"alpineTitle": "La instalación dentro del contenedor falla en un contenedor Alpine",
"alpineBody": "El script usa <code>apt-get</code>, que Alpine no tiene. La config de passthrough del LXC sigue siendo válida — solo instala el runtime de Coral manualmente con <code>apk add</code> siguiendo la guía de Google para Alpine, o usa un contenedor basado en Debian si no necesitas la huella más pequeña.",
"alpineTitle": "Contenedor Alpine / Arch / RHEL / SUSE — runtime no instalado",
"alpineBody": "Si elegiste <em>modo passthrough-only</em> cuando el script lo preguntó, la config del LXC se escribió y el dispositivo Coral es visible dentro del contenedor, pero el runtime <code>libedgetpu</code> no está instalado. Es así por diseño: el repo APT de Google solo se publica para Debian/Ubuntu. Instala el runtime manualmente con el gestor de paquetes de tu distro (Alpine: <code>apk add</code>; Arch: AUR; RHEL/SUSE: compilar desde fuente) siguiendo la guía oficial de Google, o usa un contenedor de aplicación que incluya el runtime — la imagen Docker de Frigate es el ejemplo canónico: solo expone el dispositivo con <code>--device /dev/apex_0:/dev/apex_0</code> (M.2) o el bind mount USB que el script ya escribió (USB).",
"frigateTitle": "Frigate dice 'Coral EdgeTPU detected but not available'",
"frigateBody": "Casi siempre es un problema de permisos dentro del contenedor. Frigate corre como root por defecto; comprueba que el usuario root está en el grupo <code>plugdev</code> dentro del contenedor (para USB), y que el proceso puede leer <code>/dev/apex_0</code> (para M.2). <code>ls -l /dev/apex_0</code> desde dentro del contenedor debería mostrar el grupo <code>apex</code> — si no, añade el alineamiento de GID a <code>/etc/group</code> o cambia el contenedor a modo privilegiado.",
"logsTitle": "Revisa los logs del host y del contenedor",

View File

@@ -53,6 +53,32 @@
"sparklineTitle": "El sparkline es significativo",
"sparklineBody": "La tarjeta de temperatura dibuja una traza de 5 minutos bajo el valor, con la línea y el degradado siguiendo el mismo par Warning/Critical documentado arriba. Es la forma más rápida de ver si el host está en escalada térmica sin abrir la modal de detalle."
},
"processes": {
"heading": "Acceso directo: top procesos por CPU / Memoria",
"intro": "Las tarjetas CPU Usage y Memory son clicables. Al pulsar cualquiera de ellas se abre una lista ordenable con los 25 procesos top — la tarjeta de CPU ordena por <code>%CPU</code>, la de Memory ordena por memoria residente (RSS). Ambas tiran de <code>/api/processes?sort=cpu|mem&limit=25</code>, que ejecuta un único <code>ps -eo pid,user,pcpu,pmem,rss,comm</code> por refresco.",
"listTitle": "La modal con la lista",
"listItems": [
"<strong>Auto-refresco</strong> — la lista vuelve a obtener datos cada 5 s mientras el diálogo está abierto. Al cerrar el diálogo se detiene todo el polling.",
"<strong>Caja de filtro</strong> — busca por command, user o PID sin volver a pedir datos al servidor.",
"<strong>Barra de progreso en línea</strong> — la columna de la métrica primaria dibuja una barra escalada al mayor valor de la lista filtrada, para que el orden visual se mantenga aunque ningún proceso esté cerca del 100 %.",
"<strong>Layout móvil</strong> — por debajo de 640 px las columnas PID y User desaparecen para que Command, CPU % y Memory sigan cabiendo sin scroll horizontal."
],
"captureListAlt": "Modal Top processes by Memory — tabla con columnas PID, USER, COMMAND, CPU %, Memory ordenada por RSS",
"captureListCaption": "La tarjeta Memory abre la lista ordenada por RSS (acento índigo). La tarjeta CPU abre la misma lista ordenada por %CPU (acento azul).",
"detailTitle": "Detalle por proceso",
"detailIntro": "Al pulsar cualquier fila de la lista se abre una segunda modal con la foto en vivo completa de ese proceso, servida desde <code>/api/processes/&lt;pid&gt;</code>. Cuatro secciones:",
"detailItems": [
"<strong>Overview</strong> — estado (<code>R</code>/<code>S</code>/<code>D</code>/<code>Z</code>/…), proceso padre (<code>PPid</code> + <code>comm</code> del padre), número de hilos, FDs abiertos, usuario y grupo.",
"<strong>Resources</strong> — CPU %, Memoria %, Resident (RSS), Virtual size, Swap, bytes de I/O de lectura y escritura.",
"<strong>Command</strong> — nombre corto (<code>comm</code>), línea de comandos completa, ruta del ejecutable y directorio de trabajo.",
"<strong>Lifetime</strong> — timestamp de arranque y tiempo transcurrido en ejecución."
],
"detailRefresh": "La modal de detalle se refresca cada 3 s mientras está abierta. Si el proceso termina con la modal abierta, el siguiente refresco muestra <em>Process exited</em> en vez de datos obsoletos — esperable para procesos efímeros como <code>pct exec</code> o subprocesos de backup.",
"captureDetailAlt": "Modal de detalle de proceso — secciones Overview, Resources, Command y Lifetime para un único PID",
"captureDetailCaption": "Modal de detalle por proceso abierta desde una fila de la lista. El color de acento sigue al de la tarjeta que la abrió (azul para CPU, índigo para Memory).",
"sourceTitle": "De dónde salen los datos",
"sourceBody": "<code>/api/processes/&lt;pid&gt;</code> lee directamente <code>/proc/&lt;pid&gt;/cmdline</code>, <code>/exe</code>, <code>/cwd</code>, <code>/status</code>, <code>/io</code> y <code>/fd</code>, y llama a <code>ps -o lstart=,etime=,pcpu=,pmem= -p &lt;pid&gt;</code> para los campos en vivo que el kernel no expone en <code>/proc</code>. UID y GID se resuelven a nombre de usuario / grupo con los módulos <code>pwd</code> / <code>grp</code> de Python. Ambos endpoints son handlers HTTP puros bajo demanda — sin daemon, sin sampling en background. No corre nada en el servidor mientras la modal esté cerrada."
},
"middle": {
"heading": "Medio: gráficas de métricas del nodo",
"body1": "Bajo la fila superior se encuentra el componente <code>NodeMetricsCharts</code> — gráficas históricas de CPU, memoria y E/S de disco tomadas del propio almacén RRD de Proxmox vía <code>/api/node/metrics</code>. Un selector de timeframe alterna entre <em>1 hora / 24 horas / 7 días / 30 días / 1 año</em>; la resolución de los datos baja a medida que crece la ventana para que la gráfica se mantenga fluida.",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 436 KiB

After

Width:  |  Height:  |  Size: 500 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 KiB