fix(oci): start OCI containers on any node of a cluster

This commit is contained in:
MacRimi
2026-09-28 19:06:07 +02:00
parent 297c026c95
commit 79547dec35
11 changed files with 159 additions and 49 deletions
+2 -1
View File
@@ -742,7 +742,8 @@ def _lxc_shares_host_network(vmid):
text = handle.read().split("\n[", 1)[0] text = handle.read().split("\n[", 1)[0]
except (OSError, ValueError): except (OSError, ValueError):
return False return False
return ("lxc.include: /etc/pve/lxc/proxmenux-host-monitor" in text return ("lxc.include: /etc/pve/proxmenux/host-monitor" in text
or "lxc.include: /etc/pve/lxc/proxmenux-host-monitor" in text
or ("lxc.net.0.type: none" in text and not re.search(r"^net\d+:", text, re.M))) or ("lxc.net.0.type: none" in text and not re.search(r"^net\d+:", text, re.M)))
+32 -27
View File
@@ -58,11 +58,11 @@
"A gasket DKMS registration is still present:": "Todavía existe un registro de gasket en DKMS:", "A gasket DKMS registration is still present:": "Todavía existe un registro de gasket en DKMS:",
"A host bind mount cannot be included in vzdump": "Un bind mount del host no se puede incluir en vzdump", "A host bind mount cannot be included in vzdump": "Un bind mount del host no se puede incluir en vzdump",
"A host firewall rule is only valid for a host-monitor profile": "Una regla del cortafuegos del host solo es válida en un perfil de monitor del host", "A host firewall rule is only valid for a host-monitor profile": "Una regla del cortafuegos del host solo es válida en un perfil de monitor del host",
"A host mount is not part of the journal; recovery blocked": "Un montaje host no es parte de la revista; recuperación bloqueada", "A host mount is not part of the journal; recovery blocked": "Un montaje del host no figura en el diario de la operación; recuperación bloqueada",
"A host reboot is required after this change.": "Es necesario reiniciar el host después de este cambio.", "A host reboot is required after this change.": "Es necesario reiniciar el host después de este cambio.",
"A host reboot is required before starting the VM. Reboot now?": "Es necesario reiniciar el host antes de iniciar la VM. ¿Reiniciar ahora?", "A host reboot is required before starting the VM. Reboot now?": "Es necesario reiniciar el host antes de iniciar la VM. ¿Reiniciar ahora?",
"A job with this ID already exists.": "Ya existe un trabajo con este ID.", "A job with this ID already exists.": "Ya existe un trabajo con este ID.",
"A journal already exists; review or recover it before trying again": "Ya existe una revista; revisarla o recuperarla antes de intentarlo de nuevo", "A journal already exists; review or recover it before trying again": "Ya existe un diario de operación; revísalo o recupéralo antes de volver a intentarlo",
"A keyfile is installed at:": "un archivo de claves está instalado en:", "A keyfile is installed at:": "un archivo de claves está instalado en:",
"A legacy gasket-dkms package was found on this host, but no Coral M.2 / PCIe hardware is present.": "Se ha encontrado un paquete heredado gasket-dkms en este host, pero no hay ningún dispositivo Coral M.2/PCIe.", "A legacy gasket-dkms package was found on this host, but no Coral M.2 / PCIe hardware is present.": "Se ha encontrado un paquete heredado gasket-dkms en este host, pero no hay ningún dispositivo Coral M.2/PCIe.",
"A managed rootfs and an unprivileged container are required": "Un rootf gestionado y un contenedor no privilegiado son necesarios", "A managed rootfs and an unprivileged container are required": "Un rootf gestionado y un contenedor no privilegiado son necesarios",
@@ -112,7 +112,7 @@
"A system reboot is recommended to ensure all changes take effect.": "Se recomienda reiniciar el sistema para garantizar que todos los cambios surtan efecto.", "A system reboot is recommended to ensure all changes take effect.": "Se recomienda reiniciar el sistema para garantizar que todos los cambios surtan efecto.",
"A third party companion app available to Plex server owners to allow their users to request, review and discover content.": "Una aplicación compañera de terceros disponible para los propietarios de servidores Plex para permitir a sus usuarios solicitar, revisar y descubrir contenido.", "A third party companion app available to Plex server owners to allow their users to request, review and discover content.": "Una aplicación compañera de terceros disponible para los propietarios de servidores Plex para permitir a sus usuarios solicitar, revisar y descubrir contenido.",
"A third-party client for self-hosted server and self-hosted server, remote access management interface, remote access to installed applications.": "Un cliente de terceros para servidor auto hospedado y servidor auto hospedado, interfaz de gestión de acceso remoto, acceso remoto a aplicaciones instaladas.", "A third-party client for self-hosted server and self-hosted server, remote access management interface, remote access to installed applications.": "Un cliente de terceros para servidor auto hospedado y servidor auto hospedado, interfaz de gestión de acceso remoto, acceso remoto a aplicaciones instaladas.",
"A tmpfs mount is not part of the journal; recovery blocked": "Un montaje de tmpfs no es parte de la revista; recuperación bloqueada", "A tmpfs mount is not part of the journal; recovery blocked": "Un montaje tmpfs no figura en el diario de la operación; recuperación bloqueada",
"A tmpfs mount overlaps another mount": "Un montaje de tmpfs superpone otro montaje", "A tmpfs mount overlaps another mount": "Un montaje de tmpfs superpone otro montaje",
"A tunneling daemon by Cloudflare that safely exposes your web servers into the internet.": "Un daemon de túnel por Cloudflare que expone con seguridad sus servidores web en Internet.", "A tunneling daemon by Cloudflare that safely exposes your web servers into the internet.": "Un daemon de túnel por Cloudflare que expone con seguridad sus servidores web en Internet.",
"A versatile file conversion tool that supports multiple formats.": "Una herramienta de conversión de archivos versátil que soporta múltiples formatos.", "A versatile file conversion tool that supports multiple formats.": "Una herramienta de conversión de archivos versátil que soporta múltiples formatos.",
@@ -313,7 +313,7 @@
"All images are downloaded and verified first, and native backups are taken with the stack stopped. Contracts are published after the whole set is checked. If anything fails, all members are recovered.": "Todas las imágenes se descargan y verifican primero, y los backups nativos se toman con la pila parada. Los contratos se publican después de que se revise todo el conjunto. Si algo falla, todos los miembros se recuperan.", "All images are downloaded and verified first, and native backups are taken with the stack stopped. Contracts are published after the whole set is checked. If anything fails, all members are recovered.": "Todas las imágenes se descargan y verifican primero, y los backups nativos se toman con la pila parada. Los contratos se publican después de que se revise todo el conjunto. Si algo falla, todos los miembros se recuperan.",
"All images imported and configured successfully": "Todas las imágenes importadas y configuradas correctamente.", "All images imported and configured successfully": "Todas las imágenes importadas y configuradas correctamente.",
"All imports failed": "Todas las importaciones fallaron", "All imports failed": "Todas las importaciones fallaron",
"All of them are removed.": "Todos son eliminados.", "All of them are removed.": "Se eliminan todos.",
"All partitions and metadata removed.": "Se eliminaron todas las particiones y metadatos.", "All partitions and metadata removed.": "Se eliminaron todas las particiones y metadatos.",
"All physical interfaces from backup are present on target": "Todas las interfaces físicas de la copia de seguridad están presentes en el objetivo", "All physical interfaces from backup are present on target": "Todas las interfaces físicas de la copia de seguridad están presentes en el objetivo",
"All stack members are updated together. Main CT:": "Todos los miembros de la pila se actualizan juntos. CT principal:", "All stack members are updated together. Main CT:": "Todos los miembros de la pila se actualizan juntos. CT principal:",
@@ -347,8 +347,8 @@
"An executable required by the adapter is missing in the new image": "Un ejecutable necesario para el adaptador falta en la nueva imagen", "An executable required by the adapter is missing in the new image": "Un ejecutable necesario para el adaptador falta en la nueva imagen",
"An fstab entry already exists for:": "Ya existe una entrada fstab para:", "An fstab entry already exists for:": "Ya existe una entrada fstab para:",
"An image probe container was started externally": "Un contenedor de sonda de imagen se inició externamente", "An image probe container was started externally": "Un contenedor de sonda de imagen se inició externamente",
"An include is not part of the journal; recovery blocked": "Una inclusión no es parte de la revista; recuperación bloqueada", "An include is not part of the journal; recovery blocked": "Un include no figura en el diario de la operación; recuperación bloqueada",
"An include was modified outside the journal; recovery blocked": "Una incluye fue modificada fuera de la revista; recuperación bloqueada", "An include was modified outside the journal; recovery blocked": "Un include se modificó fuera del diario de la operación; recuperación bloqueada",
"An open source generative AI development platform for building AI Agents and LLM workflows": "Una plataforma de desarrollo de AI generativa de código abierto para la construcción de agentes AI y flujos de trabajo LLM", "An open source generative AI development platform for building AI Agents and LLM workflows": "Una plataforma de desarrollo de AI generativa de código abierto para la construcción de agentes AI y flujos de trabajo LLM",
"An operation of this installation has not finished; recover it from the management menu before removing it": "Una operación de esta instalación no ha terminado; recuperarla del menú de gestión antes de eliminarla", "An operation of this installation has not finished; recover it from the management menu before removing it": "Una operación de esta instalación no ha terminado; recuperarla del menú de gestión antes de eliminarla",
"An update does not accept configuration changes": "Una actualización no acepta cambios de configuración", "An update does not accept configuration changes": "Una actualización no acepta cambios de configuración",
@@ -361,7 +361,7 @@
"Analyzing selected disks...": "Analizando discos seleccionados...", "Analyzing selected disks...": "Analizando discos seleccionados...",
"Analyzing system for available PCIe storage devices...": "Analizando el sistema para dispositivos de almacenamiento PCIe disponibles...", "Analyzing system for available PCIe storage devices...": "Analizando el sistema para dispositivos de almacenamiento PCIe disponibles...",
"Another OCI operation is using the instance registry": "Otra operación OCI está utilizando el registro de instancias", "Another OCI operation is using the instance registry": "Otra operación OCI está utilizando el registro de instancias",
"Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Otra operación OCI está utilizando el registro de instancias. Espere a que termine y abra este menú de nuevo; no se modifica ningún contenedor.", "Another OCI operation is using the instance registry. Wait for it to finish and open this menu again; no container is modified.": "Otra operación OCI está usando el registro de instancias. Espera a que termine y vuelve a abrir este menú; no se modifica ningún contenedor.",
"Another OCI operation is using the registry. This operation was not started.": "Otro operación OCI está utilizando el registro. Esta operación no se inició.", "Another OCI operation is using the registry. This operation was not started.": "Otro operación OCI está utilizando el registro. Esta operación no se inició.",
"Another instance uses": "Otro caso utiliza", "Another instance uses": "Otro caso utiliza",
"Another stack operation is pending": "Hay otra operación de pila pendiente", "Another stack operation is pending": "Hay otra operación de pila pendiente",
@@ -1087,7 +1087,7 @@
"Container must be stopped before conversion": "El contenedor debe detenerse antes de la conversión.", "Container must be stopped before conversion": "El contenedor debe detenerse antes de la conversión.",
"Container prepared for the stack:": "Contenedor preparado para la pila:", "Container prepared for the stack:": "Contenedor preparado para la pila:",
"Container recreated": "Container recreated", "Container recreated": "Container recreated",
"Container removed:": "Container removed:", "Container removed:": "Contenedor eliminado:",
"Container restarted successfully": "El contenedor se reinició correctamente", "Container restarted successfully": "El contenedor se reinició correctamente",
"Container running steadily": "Contenedor funcionando de manera constante", "Container running steadily": "Contenedor funcionando de manera constante",
"Container started": "Container started", "Container started": "Container started",
@@ -1230,6 +1230,7 @@
"Could not create or access directory:": "No se pudo crear o acceder al directorio:", "Could not create or access directory:": "No se pudo crear o acceder al directorio:",
"Could not create temporary directory:": "No se pudo crear el directorio temporal:", "Could not create temporary directory:": "No se pudo crear el directorio temporal:",
"Could not create temporary working directory.": "No se pudo crear un directorio de trabajo temporal.", "Could not create temporary working directory.": "No se pudo crear un directorio de trabajo temporal.",
"Could not create the ProxMenux folder in /etc/pve": "No se pudo crear la carpeta de ProxMenux en /etc/pve",
"Could not create the container:": "No podía crear el contenedor:", "Could not create the container:": "No podía crear el contenedor:",
"Could not create the initial administrator": "No podía crear el administrador inicial", "Could not create the initial administrator": "No podía crear el administrador inicial",
"Could not create the service:": "No podía crear el servicio:", "Could not create the service:": "No podía crear el servicio:",
@@ -1998,6 +1999,7 @@
"Every fail2ban jail ships disabled. Enable the ones you need in /config/fail2ban/jail.local, taking the ready-made jails in /config/fail2ban/jail.d/ as reference, then restart the container.": "Cada nave de prisión de fail2ban discapacitados. Habilitar los que necesites en /config/fail2ban/jail.local, tomando las cárceles listas en /config/fail2ban/jail.d/ como referencia, luego reiniciar el contenedor.", "Every fail2ban jail ships disabled. Enable the ones you need in /config/fail2ban/jail.local, taking the ready-made jails in /config/fail2ban/jail.d/ as reference, then restart the container.": "Cada nave de prisión de fail2ban discapacitados. Habilitar los que necesites en /config/fail2ban/jail.local, tomando las cárceles listas en /config/fail2ban/jail.d/ como referencia, luego reiniciar el contenedor.",
"Every hour": "Cada hora", "Every hour": "Cada hora",
"Every member of the stack is back to its previous installation.": "Cada miembro de la pila está de vuelta a su instalación anterior.", "Every member of the stack is back to its previous installation.": "Cada miembro de la pila está de vuelta a su instalación anterior.",
"Every node of this cluster already has this file. If you restore this container on any other Proxmox host, copy it to the same path first, because the container backup does not include it:": "Todos los nodos de este clúster ya tienen este archivo. Si restauras este contenedor en cualquier otro host Proxmox, copia antes el archivo a la misma ruta, porque el backup del contenedor no lo incluye:",
"Every path in this backup is kernel-tied: the restore applies these paths automatically via the safe-subset filter and re-merges the operator's tuning.": "Cada ruta en esta copia de seguridad está vinculada al kernel: la restauración aplica estas rutas automáticamente a través del filtro de subconjunto seguro y vuelve a fusionar el ajuste del operador.", "Every path in this backup is kernel-tied: the restore applies these paths automatically via the safe-subset filter and re-merges the operator's tuning.": "Cada ruta en esta copia de seguridad está vinculada al kernel: la restauración aplica estas rutas automáticamente a través del filtro de subconjunto seguro y vuelve a fusionar el ajuste del operador.",
"Everything restorable in this backup will be restored": "Todo lo que se pueda restaurar en esta copia de seguridad será restaurado", "Everything restorable in this backup will be restored": "Todo lo que se pueda restaurar en esta copia de seguridad será restaurado",
"Exact name of the remote": "Nombre exacto del remoto", "Exact name of the remote": "Nombre exacto del remoto",
@@ -3261,7 +3263,7 @@
"LXC containers with NVIDIA passthrough:": "Contenedores LXC con transferencia NVIDIA:", "LXC containers with NVIDIA passthrough:": "Contenedores LXC con transferencia NVIDIA:",
"LXC conversion from privileged to unprivileged completed successfully!": "¡La conversión de LXC de privilegiado a no privilegiado se completó con éxito!", "LXC conversion from privileged to unprivileged completed successfully!": "¡La conversión de LXC de privilegiado a no privilegiado se completó con éxito!",
"LXC conversion from unprivileged to privileged completed successfully!": "¡La conversión de LXC de no privilegiado a privilegiado se completó con éxito!", "LXC conversion from unprivileged to privileged completed successfully!": "¡La conversión de LXC de no privilegiado a privilegiado se completó con éxito!",
"LXC entries outside the NVIDIA inventory of the journal": "LXC entradas fuera del inventario NVIDIA de la revista", "LXC entries outside the NVIDIA inventory of the journal": "Entradas LXC fuera del inventario NVIDIA del diario de la operación",
"LXC entries outside the selected acceleration profile": "LXC entradas fuera del perfil de aceleración seleccionado", "LXC entries outside the selected acceleration profile": "LXC entradas fuera del perfil de aceleración seleccionado",
"LXC entry outside the read-only NVIDIA profile": "LXC entrada fuera del perfil de NVIDIA solo lectura", "LXC entry outside the read-only NVIDIA profile": "LXC entrada fuera del perfil de NVIDIA solo lectura",
"LXC removed:": "LXC eliminado:", "LXC removed:": "LXC eliminado:",
@@ -4805,7 +4807,7 @@
"Remove iSCSI storage definition:": "Eliminar la definición de almacenamiento iSCSI:", "Remove iSCSI storage definition:": "Eliminar la definición de almacenamiento iSCSI:",
"Remove invalid port": "Eliminar puerto no válido", "Remove invalid port": "Eliminar puerto no válido",
"Remove invalid port(s)": "Eliminar puertos no válidos", "Remove invalid port(s)": "Eliminar puertos no válidos",
"Remove it? The data of its containers cannot be recovered afterwards.": "¿Eliminarlo? Los datos de sus contenedores no se podrán recuperar después.", "Remove it? The data of its containers cannot be recovered afterwards.": "¿Eliminarla? Los datos de sus contenedores no se podrán recuperar después.",
"Remove keyfile from this host": "eliminar el archivo de claves de este host", "Remove keyfile from this host": "eliminar el archivo de claves de este host",
"Remove mount point:": "Eliminar punto de montaje:", "Remove mount point:": "Eliminar punto de montaje:",
"Remove obsolete systemd-boot meta-package": "Eliminar el metapaquete obsoleto systemd-boot", "Remove obsolete systemd-boot meta-package": "Eliminar el metapaquete obsoleto systemd-boot",
@@ -4865,7 +4867,7 @@
"Removing stale VFIO entries from vfio.conf...": "Eliminando entradas VFIO obsoletas de vfio.conf...", "Removing stale VFIO entries from vfio.conf...": "Eliminando entradas VFIO obsoletas de vfio.conf...",
"Removing storage from Proxmox...": "Eliminando almacenamiento de Proxmox...", "Removing storage from Proxmox...": "Eliminando almacenamiento de Proxmox...",
"Removing system limits optimizations...": "Eliminando optimizaciones de límites del sistema...", "Removing system limits optimizations...": "Eliminando optimizaciones de límites del sistema...",
"Removing the containers...": "Removiendo los contenedores...", "Removing the containers...": "Eliminando los contenedores...",
"Removing the incomplete stack...": "Eliminando la pila incompleta...", "Removing the incomplete stack...": "Eliminando la pila incompleta...",
"Removing the previous container": "Remoción del contenedor anterior", "Removing the previous container": "Remoción del contenedor anterior",
"Removing utilities installed by ProxMenux...": "Eliminando utilidades instaladas por ProxMenux...", "Removing utilities installed by ProxMenux...": "Eliminando utilidades instaladas por ProxMenux...",
@@ -5117,7 +5119,7 @@
"Save and classify articles. Read them later. Freely.": "Guardar y clasificar artículos. Léelos más tarde. Libre.", "Save and classify articles. Read them later. Freely.": "Guardar y clasificar artículos. Léelos más tarde. Libre.",
"Save the passphrase somewhere safe NOW, before continuing.": "guarde la frase de contraseña en un lugar seguro AHORA, antes de continuar.", "Save the passphrase somewhere safe NOW, before continuing.": "guarde la frase de contraseña en un lugar seguro AHORA, antes de continuar.",
"Save this Borg target so you don't need to enter the details again?": "¿Guardar este objetivo Borg para no tener que volver a introducir los detalles?", "Save this Borg target so you don't need to enter the details again?": "¿Guardar este objetivo Borg para no tener que volver a introducir los detalles?",
"Saved record removed": "Se elimina el registro guardado", "Saved record removed": "Registro guardado eliminado",
"Saving the new configuration": "Salvando la nueva configuración", "Saving the new configuration": "Salvando la nueva configuración",
"Saving the new configuration...": "Guardando la nueva configuración...", "Saving the new configuration...": "Guardando la nueva configuración...",
"Saving the stack records...": "Guardando los registros de la pila...", "Saving the stack records...": "Guardando los registros de la pila...",
@@ -5865,7 +5867,7 @@
"The VM guest will have exclusive access to the GPU.": "El invitado de la VM tendrá acceso exclusivo a la GPU.", "The VM guest will have exclusive access to the GPU.": "El invitado de la VM tendrá acceso exclusivo a la GPU.",
"The VM is powered on. Turn it off before adding disks.": "La máquina virtual está encendida. Apáguelo antes de agregar discos.", "The VM is powered on. Turn it off before adding disks.": "La máquina virtual está encendida. Apáguelo antes de agregar discos.",
"The VM/LXC will lose access to this disk after formatting.": "El VM/LXC perderá el acceso a este disco después de formatear.", "The VM/LXC will lose access to this disk after formatting.": "El VM/LXC perderá el acceso a este disco después de formatear.",
"The VMID belongs to another container now and is not touched:": "El VMID pertenece a otro contenedor ahora y no se toca:", "The VMID belongs to another container now and is not touched:": "El VMID pertenece ahora a otro contenedor y no se toca:",
"The VMID or its contract is already in use; it is not adopted": "El VMID o su contrato ya está en uso; no es adoptado", "The VMID or its contract is already in use; it is not adopted": "El VMID o su contrato ya está en uso; no es adoptado",
"The VMID was reused or its identity is unknown; the operation is blocked": "El VMID fue reutilizado o su identidad es desconocida; la operación está bloqueada", "The VMID was reused or its identity is unknown; the operation is blocked": "El VMID fue reutilizado o su identidad es desconocida; la operación está bloqueada",
"The VMID was reused or the container is on another node; it is not overwritten": "El VMID fue reutilizado o el contenedor está en otro nodo; no está sobrescrito", "The VMID was reused or the container is on another node; it is not overwritten": "El VMID fue reutilizado o el contenedor está en otro nodo; no está sobrescrito",
@@ -5892,7 +5894,7 @@
"The application did not pass its HTTP check:": "La aplicación no superó la comprobación HTTP:", "The application did not pass its HTTP check:": "La aplicación no superó la comprobación HTTP:",
"The application did not respond in time:": "La aplicación no respondió a tiempo:", "The application did not respond in time:": "La aplicación no respondió a tiempo:",
"The application stopped during its first start:": "La aplicación se detuvo durante su primer comienzo:", "The application stopped during its first start:": "La aplicación se detuvo durante su primer comienzo:",
"The application was removed": "La solicitud fue eliminada", "The application was removed": "La aplicación se ha eliminado",
"The archive could not be extracted.": "No se pudo extraer el archivo.", "The archive could not be extracted.": "No se pudo extraer el archivo.",
"The archive destination directory is INSIDE one of the paths you are about to back up. Writing the archive there would copy the backup into itself — producing a corrupted archive, or growing without limit until the disk fills up.": "El directorio de destino del archivo está DENTRO de una de las rutas de las que está a punto de realizar una copia de seguridad. Escribir el archivo allí copiaría la copia de seguridad en sí mismo, lo que produciría un archivo corrupto o crecería sin límite hasta que el disco se llenara.", "The archive destination directory is INSIDE one of the paths you are about to back up. Writing the archive there would copy the backup into itself — producing a corrupted archive, or growing without limit until the disk fills up.": "El directorio de destino del archivo está DENTRO de una de las rutas de las que está a punto de realizar una copia de seguridad. Escribir el archivo allí copiaría la copia de seguridad en sí mismo, lo que produciría un archivo corrupto o crecería sin límite hasta que el disco se llenara.",
"The backup could not be identified; the image is not replaced": "El backup no se pudo identificar; la imagen no es reemplazada", "The backup could not be identified; the image is not replaced": "El backup no se pudo identificar; la imagen no es reemplazada",
@@ -5944,6 +5946,7 @@
"The container is not modified because a host directory is not available:": "El contenedor no se modifica porque un directorio host no está disponible:", "The container is not modified because a host directory is not available:": "El contenedor no se modifica porque un directorio host no está disponible:",
"The container no longer exists:": "El contenedor ya no existe:", "The container no longer exists:": "El contenedor ya no existe:",
"The container of a member was replaced; the assembly is not resumed": "El contenedor de un miembro fue reemplazado; la asamblea no se reanuda", "The container of a member was replaced; the assembly is not resumed": "El contenedor de un miembro fue reemplazado; la asamblea no se reanuda",
"The container runs on another node of the cluster; migrate it back to this node to remove it:": "El contenedor está en otro nodo del clúster; migra el contenedor de vuelta a este nodo para eliminarlo:",
"The container should now start as privileged": "El contenedor ahora debería comenzar como privilegiado.", "The container should now start as privileged": "El contenedor ahora debería comenzar como privilegiado.",
"The container should now start as unprivileged": "El contenedor ahora debería comenzar sin privilegios.", "The container should now start as unprivileged": "El contenedor ahora debería comenzar sin privilegios.",
"The container stopped after starting:": "El contenedor se detuvo después de comenzar:", "The container stopped after starting:": "El contenedor se detuvo después de comenzar:",
@@ -6070,7 +6073,7 @@
"The instance registry is not safe": "El registro de instancias no es seguro", "The instance registry is not safe": "El registro de instancias no es seguro",
"The journal belongs to another VMID": "El diario pertenece a otro VMID", "The journal belongs to another VMID": "El diario pertenece a otro VMID",
"The journal belongs to another stack": "El diario pertenece a otra pila", "The journal belongs to another stack": "El diario pertenece a otra pila",
"The journal has an incomplete recovery state": "La revista tiene un estado de recuperación incompleto", "The journal has an incomplete recovery state": "El diario de la operación tiene un estado de recuperación incompleto",
"The kernel module is not active:": "El módulo del núcleo no está activo:", "The kernel module is not active:": "El módulo del núcleo no está activo:",
"The kernel module of version": "El módulo del kernel de la versión.", "The kernel module of version": "El módulo del kernel de la versión.",
"The local envelope is dropped and future backups do not upload anything. Uploaded envelopes already on PBS stay intact and remain recoverable with their original passphrase.": "El sobre local se elimina y las copias de seguridad futuras no cargan nada. Los sobres cargados que ya están en PBS permanecen intactos y recuperables con su frase de contraseña original.", "The local envelope is dropped and future backups do not upload anything. Uploaded envelopes already on PBS stay intact and remain recoverable with their original passphrase.": "El sobre local se elimina y las copias de seguridad futuras no cargan nada. Los sobres cargados que ya están en PBS permanecen intactos y recuperables con su frase de contraseña original.",
@@ -6080,7 +6083,7 @@
"The managed host firewall rule could not be removed and was left unchanged.": "No se pudo eliminar la regla del cortafuegos del host gestionada por ProxMenux; se ha dejado sin cambios.", "The managed host firewall rule could not be removed and was left unchanged.": "No se pudo eliminar la regla del cortafuegos del host gestionada por ProxMenux; se ha dejado sin cambios.",
"The manifest does not match its digest": "El manifiesto no coincide con su digestión", "The manifest does not match its digest": "El manifiesto no coincide con su digestión",
"The member journal belongs to another stack operation": "El diario del miembro pertenece a otra operación de pila", "The member journal belongs to another stack operation": "El diario del miembro pertenece a otra operación de pila",
"The member journal is outside the registry": "La revista miembro está fuera del registro", "The member journal is outside the registry": "El diario del miembro está fuera del registro",
"The mount evidence does not match the verified directories": "La evidencia de montaje no coincide con los directorios verificados", "The mount evidence does not match the verified directories": "La evidencia de montaje no coincide con los directorios verificados",
"The mount source or options were not kept": "La fuente de montaje o las opciones no se guardaron", "The mount source or options were not kept": "La fuente de montaje o las opciones no se guardaron",
"The mounted source differs from the configured directory": "La fuente montada difiere del directorio configurado", "The mounted source differs from the configured directory": "La fuente montada difiere del directorio configurado",
@@ -6091,7 +6094,7 @@
"The new SSH key was pushed to the LXC via 'pct exec' on": "La nueva clave SSH se envió al LXC a través de 'pct exec' en", "The new SSH key was pushed to the LXC via 'pct exec' on": "La nueva clave SSH se envió al LXC a través de 'pct exec' en",
"The new Valkey volume contains unexpected data": "El nuevo volumen Valkey contiene datos inesperados", "The new Valkey volume contains unexpected data": "El nuevo volumen Valkey contiene datos inesperados",
"The new container did not pass validation": "El nuevo contenedor no aprobó la validación", "The new container did not pass validation": "El nuevo contenedor no aprobó la validación",
"The new container is not authorized by the operation journal": "El nuevo contenedor no está autorizado por la revista operación", "The new container is not authorized by the operation journal": "El diario de la operación no autoriza el nuevo contenedor",
"The new image adds a symbolic link in a generated path": "La nueva imagen añade un vínculo simbólico en un camino generado", "The new image adds a symbolic link in a generated path": "La nueva imagen añade un vínculo simbólico en un camino generado",
"The new image changes the PostgreSQL major version; the data must be migrated before updating": "La nueva imagen cambia la versión principal de PostgreSQL; los datos deben ser migrados antes de actualizar", "The new image changes the PostgreSQL major version; the data must be migrated before updating": "La nueva imagen cambia la versión principal de PostgreSQL; los datos deben ser migrados antes de actualizar",
"The new image could not be installed": "La nueva imagen no se puede instalar", "The new image could not be installed": "La nueva imagen no se puede instalar",
@@ -6134,15 +6137,15 @@
"The postgres user was not found in the image": "El usuario postgres no fue encontrado en la imagen", "The postgres user was not found in the image": "El usuario postgres no fue encontrado en la imagen",
"The prepared directory escapes the rootfs:": "El directorio preparado escapa a los rootfs:", "The prepared directory escapes the rootfs:": "El directorio preparado escapa a los rootfs:",
"The preselected VMID does not exist on this host:": "El VMID preseleccionado no existe en este host:", "The preselected VMID does not exist on this host:": "El VMID preseleccionado no existe en este host:",
"The previous native backup will be restored. Shared host directories are not reverted. Displaced disks are kept.": "El backup nativo anterior será restaurado. Los directorios de host compartidos no son revertidos. Se guardan discos desplazados.", "The previous native backup will be restored. Shared host directories are not reverted. Displaced disks are kept.": "Se restaurará el backup nativo anterior. Los directorios compartidos del host no se revierten. Los discos desplazados se conservan.",
"The previous stack contract is not safe; review it before reusing it": "El contrato de pila anterior no es seguro; revíselo antes de reutilizarlo", "The previous stack contract is not safe; review it before reusing it": "El contrato de pila anterior no es seguro; revíselo antes de reutilizarlo",
"The previous stack contract is not valid; it is not archived automatically": "El contrato de pila anterior no es válido; no se archiva automáticamente", "The previous stack contract is not valid; it is not archived automatically": "El contrato de pila anterior no es válido; no se archiva automáticamente",
"The previous stack contract still has containers or VMs:": "El contrato de pila anterior todavía tiene contenedores o VMs:", "The previous stack contract still has containers or VMs:": "El contrato de pila anterior todavía tiene contenedores o VMs:",
"The private address is already assigned to another container:": "La dirección privada ya está asignada a otro contenedor:", "The private address is already assigned to another container:": "La dirección privada ya está asignada a otro contenedor:",
"The private bridge does not have the expected address:": "El puente privado no tiene la dirección prevista:", "The private bridge does not have the expected address:": "El puente privado no tiene la dirección prevista:",
"The private journal has an unsafe owner or permissions": "La revista privada tiene un propietario inseguro o permisos", "The private journal has an unsafe owner or permissions": "El diario privado tiene un propietario o permisos inseguros",
"The private network allocator was not found": "El aleator de la red privada no fue encontrado", "The private network allocator was not found": "El aleator de la red privada no fue encontrado",
"The private network is still used by another container and is kept:": "La red privada sigue siendo utilizada por otro contenedor y se mantiene:", "The private network is still used by another container and is kept:": "Otro contenedor sigue usando la red privada, así que se conserva:",
"The private network must be assigned automatically": "La red privada debe ser asignada automáticamente", "The private network must be assigned automatically": "La red privada debe ser asignada automáticamente",
"The privileged deployment does not include the required explicit consent": "El despliegue privilegiado no incluye el consentimiento explícito necesario", "The privileged deployment does not include the required explicit consent": "El despliegue privilegiado no incluye el consentimiento explícito necesario",
"The prlimit soft value exceeds the hard value": "El valor prlimit blando supera el valor duro", "The prlimit soft value exceeds the hard value": "El valor prlimit blando supera el valor duro",
@@ -6188,7 +6191,7 @@
"The script will preconfigure the selected GPU now and finalize hardware binding after reboot.": "El script preconfigurará la GPU seleccionada ahora y finalizará el enlace del hardware después del reinicio.", "The script will preconfigure the selected GPU now and finalize hardware binding after reboot.": "El script preconfigurará la GPU seleccionada ahora y finalizará el enlace del hardware después del reinicio.",
"The selected AMD GPU does not report FLR reset support": "La GPU AMD seleccionada no informa compatibilidad con el restablecimiento de FLR", "The selected AMD GPU does not report FLR reset support": "La GPU AMD seleccionada no informa compatibilidad con el restablecimiento de FLR",
"The selected AMD GPU is currently in power state D3cold": "La GPU AMD seleccionada se encuentra actualmente en estado de energía D3cold", "The selected AMD GPU is currently in power state D3cold": "La GPU AMD seleccionada se encuentra actualmente en estado de energía D3cold",
"The selected CT does not match its OCI record. Its configuration will not be modified or deleted.": "El CT seleccionado no coincide con su registro OCI. Su configuración no será modificada ni eliminada.", "The selected CT does not match its OCI record. Its configuration will not be modified or deleted.": "El CT seleccionado no coincide con su registro OCI. Su configuración no se modificará ni se eliminará.",
"The selected GPU changed": "La GPU seleccionada cambió", "The selected GPU changed": "La GPU seleccionada cambió",
"The selected GPU configuration already exists in this container.": "La configuración de GPU seleccionada ya existe en este contenedor.", "The selected GPU configuration already exists in this container.": "La configuración de GPU seleccionada ya existe en este contenedor.",
"The selected GPU device does not exist:": "El dispositivo GPU seleccionado no existe:", "The selected GPU device does not exist:": "El dispositivo GPU seleccionado no existe:",
@@ -6262,10 +6265,10 @@
"The storage does not accept backups:": "El almacenamiento no admite backups:", "The storage does not accept backups:": "El almacenamiento no admite backups:",
"The storage has been removed and the disk unmounted.": "Se eliminó el almacenamiento y se desmontó el disco.", "The storage has been removed and the disk unmounted.": "Se eliminó el almacenamiento y se desmontó el disco.",
"The sysctl content was modified outside the saved record": "El contenido de sysctl fue modificado fuera del registro guardado", "The sysctl content was modified outside the saved record": "El contenido de sysctl fue modificado fuera del registro guardado",
"The sysctl include is a link:": "El sysctl incluye un enlace:", "The sysctl include is a link:": "El include de sysctl es un enlace:",
"The sysctl include is not a safe host file": "El sysctl incluye no es un archivo host seguro", "The sysctl include is not a safe host file": "El include de sysctl no es un archivo seguro del host",
"The sysctl include is not restored over a symbolic link": "El sysctl incluye no se restaura sobre un enlace simbólico", "The sysctl include is not restored over a symbolic link": "El include de sysctl no se restaura sobre un enlace simbólico",
"The sysctl include is unknown or differs from the saved record": "El sysctl incluye es desconocido o difiere del registro guardado", "The sysctl include is unknown or differs from the saved record": "El include de sysctl es desconocido o difiere del registro guardado",
"The temporary password could not be retrieved.": "La contraseña temporal no se puede recuperar.", "The temporary password could not be retrieved.": "La contraseña temporal no se puede recuperar.",
"The test will continue even if you close this terminal.": "La prueba continuará incluso si cierra esta terminal.", "The test will continue even if you close this terminal.": "La prueba continuará incluso si cierra esta terminal.",
"The tmpfs mounts of the container differ from the saved record": "Los montajes tmpfs del contenedor difieren del registro guardado", "The tmpfs mounts of the container differ from the saved record": "Los montajes tmpfs del contenedor difieren del registro guardado",
@@ -6289,7 +6292,7 @@
"Then change the VM display to none (vga: none) when the system is stable.": "Luego cambie la visualización de VM a ninguno (vga: ninguno) cuando el sistema esté estable.", "Then change the VM display to none (vga: none) when the system is stable.": "Luego cambie la visualización de VM a ninguno (vga: ninguno) cuando el sistema esté estable.",
"Then run this option again:": "Luego ejecute esta opción nuevamente:", "Then run this option again:": "Luego ejecute esta opción nuevamente:",
"Then update /etc/fstab on the host with the same options.": "Luego actualice /etc/fstab en el host con las mismas opciones.", "Then update /etc/fstab on the host with the same options.": "Luego actualice /etc/fstab en el host con las mismas opciones.",
"There are extra disks or bind mounts outside the journal; the rootfs is not replaced": "Hay discos extras o monturas bind fuera de la revista; los rootfs no es reemplazado", "There are extra disks or bind mounts outside the journal; the rootfs is not replaced": "Hay discos o bind mounts adicionales fuera del diario de la operación; el rootfs no se reemplaza",
"There is no temporary container of this operation to keep the current disks": "No hay contenedor temporal de esta operación para mantener los discos actuales", "There is no temporary container of this operation to keep the current disks": "No hay contenedor temporal de esta operación para mantener los discos actuales",
"There is no verified backup; a modified container is not touched": "No hay backup verificado; un contenedor modificado no se toca", "There is no verified backup; a modified container is not touched": "No hay backup verificado; un contenedor modificado no se toca",
"These Proxmox resources were added outside ProxMenux:": "Se añadieron estos recursos en Proxmox fuera de ProxMenux:", "These Proxmox resources were added outside ProxMenux:": "Se añadieron estos recursos en Proxmox fuera de ProxMenux:",
@@ -6618,7 +6621,7 @@
"Unsupported tmpfs options": "Opciones de tmpfs sin soporte", "Unsupported tmpfs options": "Opciones de tmpfs sin soporte",
"Unsupported volume options:": "Opciones de volumen no admitidas:", "Unsupported volume options:": "Opciones de volumen no admitidas:",
"Untrusted or modified NVIDIA hook": "Gancho NVIDIA sin confianza o modificado", "Untrusted or modified NVIDIA hook": "Gancho NVIDIA sin confianza o modificado",
"Unused image removed from the cache:": "Imagen no utilizada extraída del caché:", "Unused image removed from the cache:": "Imagen sin uso eliminada de la caché:",
"Unused images removed from the cache:": "Imágenes sin uso eliminadas de la caché:", "Unused images removed from the cache:": "Imágenes sin uso eliminadas de la caché:",
"Update": "Actualización", "Update": "Actualización",
"Update Available": "Actualización disponible", "Update Available": "Actualización disponible",
@@ -6747,6 +6750,7 @@
"Username on the Borg server that runs \"borg serve\" (typically \"borg\"). This is NOT the admin/root user of the server — that one is asked later only if you choose \"Generate a new key and authorize it\".": "nombre de usuario en el servidor Borg que ejecuta \"borg server\" (normalmente \"borg\").Este NO es el usuario administrador/root del servidor; ese se solicita más tarde solo si elige \"Generar una nueva clave y autorizarla\".", "Username on the Borg server that runs \"borg serve\" (typically \"borg\"). This is NOT the admin/root user of the server — that one is asked later only if you choose \"Generate a new key and authorize it\".": "nombre de usuario en el servidor Borg que ejecuta \"borg server\" (normalmente \"borg\").Este NO es el usuario administrador/root del servidor; ese se solicita más tarde solo si elige \"Generar una nueva clave y autorizarla\".",
"Username:": "Nombre de usuario:", "Username:": "Nombre de usuario:",
"Users:": "Usuarios:", "Users:": "Usuarios:",
"Uses lxc.include with /etc/pve/proxmenux/host-monitor, which every node of the cluster shares; vzdump does not include it, so it must be copied when restoring outside the cluster.": "Usa lxc.include con /etc/pve/proxmenux/host-monitor, que comparten todos los nodos del clúster; vzdump no lo incluye, así que hay que copiarlo al restaurar fuera del clúster.",
"Using UUID is recommended over /dev/sdX.": "Se recomienda usar UUID en lugar de /dev/sdX.", "Using UUID is recommended over /dev/sdX.": "Se recomienda usar UUID en lugar de /dev/sdX.",
"Using advanced configuration": "Usando configuración avanzada", "Using advanced configuration": "Usando configuración avanzada",
"Using default Proxmox logo...": "Usando el logotipo predeterminado de Proxmox...", "Using default Proxmox logo...": "Usando el logotipo predeterminado de Proxmox...",
@@ -6949,6 +6953,7 @@
"Weixin (WeChat) is an instant messaging, social media, and mobile payment app developed by Tencent.": "Weixin (WeChat) es una aplicación de mensajería instantánea, redes sociales y pago móvil desarrollada por Tencent.", "Weixin (WeChat) is an instant messaging, social media, and mobile payment app developed by Tencent.": "Weixin (WeChat) es una aplicación de mensajería instantánea, redes sociales y pago móvil desarrollada por Tencent.",
"What cannot be translated:": "Lo que no puede traducirse:", "What cannot be translated:": "Lo que no puede traducirse:",
"What do you want to do?": "¿Qué es lo que quieres hacer?", "What do you want to do?": "¿Qué es lo que quieres hacer?",
"What was left of containers that no longer exist has been removed:": "Se ha eliminado lo que quedaba de contenedores que ya no existen:",
"What would you like to do?": "¿Qué te gustaría hacer?", "What would you like to do?": "¿Qué te gustaría hacer?",
"When asked to select a disk, click Load Driver and load the VirtIO drivers.": "Cuando se le solicite seleccionar un disco, haga clic en Cargar controlador y cargue los controladores VirtIO.", "When asked to select a disk, click Load Driver and load the VirtIO drivers.": "Cuando se le solicite seleccionar un disco, haga clic en Cargar controlador y cargue los controladores VirtIO.",
"When this GPU is passed through to a VM, the Proxmox host will lose all video output on the physical monitor.": "Cuando esta GPU pasa a una VM, el host Proxmox perderá toda la salida de video en el monitor físico.", "When this GPU is passed through to a VM, the Proxmox host will lose all video output on the physical monitor.": "Cuando esta GPU pasa a una VM, el host Proxmox perderá toda la salida de video en el monitor físico.",
+5 -3
View File
@@ -485,9 +485,11 @@ so the monitor sees the host's real processor count.
Proxmox does not accept `lxc.namespace.share.*` directly in CT configuration. Proxmox does not accept `lxc.namespace.share.*` directly in CT configuration.
The installer uses supported `lxc.include` referencing the static companion The installer uses supported `lxc.include` referencing the static companion
`/etc/pve/lxc/proxmenux-host-monitor`. This file persists across host reboots but `/etc/pve/proxmenux/host-monitor`. `/etc/pve/proxmenux` is the same on every node
is NOT included in a CT vzdump. Preserve/recreate it when restoring on another of a cluster, unlike `/etc/pve/lxc`, which is the folder of the local node, so a
host, in addition to restoring managed volumes. Full restore/image replacement migrated container finds it. It is NOT included in a CT vzdump: copy it when
restoring outside the cluster, in addition to restoring managed volumes.
Installations made before this keep `/etc/pve/lxc/proxmenux-host-monitor`. Full restore/image replacement
have not been tested. No custom supervisor or image entrypoint is introduced. have not been tested. No custom supervisor or image entrypoint is introduced.
DeepSeek OCR remains deferred at the user's request: registry inspection on DeepSeek OCR remains deferred at the user's request: registry inspection on
+2 -2
View File
@@ -37,7 +37,7 @@
"Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.", "Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.",
"Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.", "Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.",
"LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.", "LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.",
"Uses lxc.include with /etc/pve/lxc/proxmenux-host-monitor; this file is not included in vzdump and must be kept when restoring on another host.", "Uses lxc.include with /etc/pve/proxmenux/host-monitor, which every node of the cluster shares; vzdump does not include it, so it must be copied when restoring outside the cluster.",
"The CPU limit is applied as cpulimit, without hiding processors through affinity." "The CPU limit is applied as cpulimit, without hiding processors through affinity."
], ],
"mini_changelog": [], "mini_changelog": [],
@@ -489,7 +489,7 @@
"host_network_namespace": true, "host_network_namespace": true,
"host_memory_bytes": 16110522368, "host_memory_bytes": 16110522368,
"shutdown_start_passed": true, "shutdown_start_passed": true,
"companion_include": "/etc/pve/lxc/proxmenux-host-monitor", "companion_include": "/etc/pve/proxmenux/host-monitor",
"companion_included_in_vzdump": false, "companion_included_in_vzdump": false,
"rolling_tag_validation": "only-observed-digest", "rolling_tag_validation": "only-observed-digest",
"host_cpu_count": 16, "host_cpu_count": 16,
+2 -2
View File
@@ -37,7 +37,7 @@
"Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.", "Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.",
"Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.", "Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.",
"LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.", "LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.",
"Uses lxc.include with /etc/pve/lxc/proxmenux-host-monitor; this file is not included in vzdump and must be kept when restoring on another host.", "Uses lxc.include with /etc/pve/proxmenux/host-monitor, which every node of the cluster shares; vzdump does not include it, so it must be copied when restoring outside the cluster.",
"The CPU limit is applied as cpulimit, without hiding processors through affinity." "The CPU limit is applied as cpulimit, without hiding processors through affinity."
], ],
"mini_changelog": [], "mini_changelog": [],
@@ -657,7 +657,7 @@
"host_network_namespace": true, "host_network_namespace": true,
"host_memory_bytes": 16110522368, "host_memory_bytes": 16110522368,
"shutdown_start_passed": true, "shutdown_start_passed": true,
"companion_include": "/etc/pve/lxc/proxmenux-host-monitor", "companion_include": "/etc/pve/proxmenux/host-monitor",
"companion_included_in_vzdump": false, "companion_included_in_vzdump": false,
"rolling_tag_validation": "only-observed-digest", "rolling_tag_validation": "only-observed-digest",
"cgroup_charts_observed": 144, "cgroup_charts_observed": 144,
+2 -2
View File
@@ -6,7 +6,7 @@
"Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.", "Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.",
"Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.", "Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.",
"LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.", "LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.",
"Uses lxc.include with /etc/pve/lxc/proxmenux-host-monitor; this file is not included in vzdump and must be kept when restoring on another host.", "Uses lxc.include with /etc/pve/proxmenux/host-monitor, which every node of the cluster shares; vzdump does not include it, so it must be copied when restoring outside the cluster.",
"The CPU limit is applied as cpulimit, without hiding processors through affinity." "The CPU limit is applied as cpulimit, without hiding processors through affinity."
] ]
}, },
@@ -102,7 +102,7 @@
"host_network_namespace": true, "host_network_namespace": true,
"host_memory_bytes": 16110522368, "host_memory_bytes": 16110522368,
"shutdown_start_passed": true, "shutdown_start_passed": true,
"companion_include": "/etc/pve/lxc/proxmenux-host-monitor", "companion_include": "/etc/pve/proxmenux/host-monitor",
"companion_included_in_vzdump": false, "companion_included_in_vzdump": false,
"rolling_tag_validation": "only-observed-digest", "rolling_tag_validation": "only-observed-digest",
"host_cpu_count": 16, "host_cpu_count": 16,
+2 -2
View File
@@ -6,7 +6,7 @@
"Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.", "Privileged access to the host PID/network and unconfined AppArmor: requires confirmation. Trusted networks only; the host firewall is the one that applies.",
"Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.", "Neither docker.sock nor the host root directory is mounted. Docker inventory, SMART and capacity of all filesystems are not guaranteed.",
"LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.", "LXCFS is skipped only in the monitor CT so that the limited container RAM/CPU is not shown.",
"Uses lxc.include with /etc/pve/lxc/proxmenux-host-monitor; this file is not included in vzdump and must be kept when restoring on another host.", "Uses lxc.include with /etc/pve/proxmenux/host-monitor, which every node of the cluster shares; vzdump does not include it, so it must be copied when restoring outside the cluster.",
"The CPU limit is applied as cpulimit, without hiding processors through affinity." "The CPU limit is applied as cpulimit, without hiding processors through affinity."
] ]
}, },
@@ -152,7 +152,7 @@
"host_network_namespace": true, "host_network_namespace": true,
"host_memory_bytes": 16110522368, "host_memory_bytes": 16110522368,
"shutdown_start_passed": true, "shutdown_start_passed": true,
"companion_include": "/etc/pve/lxc/proxmenux-host-monitor", "companion_include": "/etc/pve/proxmenux/host-monitor",
"companion_included_in_vzdump": false, "companion_included_in_vzdump": false,
"rolling_tag_validation": "only-observed-digest", "rolling_tag_validation": "only-observed-digest",
"cgroup_charts_observed": 144, "cgroup_charts_observed": 144,
+7 -3
View File
@@ -286,8 +286,11 @@ apply_host_monitor() {
[[ -n ${HOST_MONITOR:-} ]] || return 0 [[ -n ${HOST_MONITOR:-} ]] || return 0
# PVE permits lxc.include but not namespace keys directly in the CT config. # PVE permits lxc.include but not namespace keys directly in the CT config.
# This static, cluster-persistent companion must accompany cross-host restores. # This static, cluster-persistent companion must accompany cross-host restores.
local include=/etc/pve/lxc/proxmenux-host-monitor native # /etc/pve/proxmenux is the same on every node of a cluster; /etc/pve/lxc
# is the folder of this node only.
local include=/etc/pve/proxmenux/host-monitor native
native=$'lxc.namespace.share.pid = 1\nlxc.namespace.share.net = 1' native=$'lxc.namespace.share.pid = 1\nlxc.namespace.share.net = 1'
mkdir -p /etc/pve/proxmenux || die "$(translate "Could not create the ProxMenux folder in /etc/pve")"
if [[ -e $include ]]; then if [[ -e $include ]]; then
[[ $(cat "$include") == "$native" ]] || die "$(translate "A different host monitor include already exists; it is not overwritten:") $include" [[ $(cat "$include") == "$native" ]] || die "$(translate "A different host monitor include already exists; it is not overwritten:") $include"
else else
@@ -300,7 +303,7 @@ apply_host_monitor() {
# Do not remove the Proxmox pre-start, autodev or post-stop hooks. # Do not remove the Proxmox pre-start, autodev or post-stop hooks.
set_lxc_directive lxc.hook.mount "" set_lxc_directive lxc.hook.mount ""
msg_ok "$(translate "Host monitor configured: shared PID and network namespaces, LXCFS disabled in this container")" msg_ok "$(translate "Host monitor configured: shared PID and network namespaces, LXCFS disabled in this container")"
msg_info2 "$(translate "If you restore this container on another Proxmox host, copy this file to the same path first, because the container backup does not include it:") $include" msg_info2 "$(translate "Every node of this cluster already has this file. If you restore this container on any other Proxmox host, copy it to the same path first, because the container backup does not include it:") $include"
} }
verify_host_monitor() { verify_host_monitor() {
@@ -1661,7 +1664,8 @@ fi
SYSCTL_COUNT=$(jq '.security.sysctls? // [] | length' "$DEPLOYMENT_FILE") SYSCTL_COUNT=$(jq '.security.sysctls? // [] | length' "$DEPLOYMENT_FILE")
if (( SYSCTL_COUNT > 0 )); then if (( SYSCTL_COUNT > 0 )); then
SYSCTL_INCLUDE="/etc/pve/lxc/${VMID}.proxmenux-sysctls" SYSCTL_INCLUDE="/etc/pve/proxmenux/${VMID}.sysctls"
mkdir -p /etc/pve/proxmenux || die "$(translate "Could not create the ProxMenux folder in /etc/pve")"
SYSCTL_TEMP=$(mktemp) SYSCTL_TEMP=$(mktemp)
while IFS=$'\t' read -r SYSCTL_NAME SYSCTL_VALUE; do while IFS=$'\t' read -r SYSCTL_NAME SYSCTL_VALUE; do
[[ -n $SYSCTL_NAME ]] || continue [[ -n $SYSCTL_NAME ]] || continue
+8 -2
View File
@@ -28,14 +28,20 @@ LOG_DIR = Path('/var/log/proxmenux/oci')
# Each start is marked in the console log by a pre-start hook. The hook runs # Each start is marked in the console log by a pre-start hook. The hook runs
# the script only when it exists and always succeeds: a hook that fails would # the script only when it exists and always succeeds: a hook that fails would
# stop the container from starting. # stop the container from starting.
START_MARK_SCRIPT = Path(__file__).resolve().with_name('oci_console_mark.sh') # The installed engine, not this file: the installer runs a copy of the
# engine from a temporary directory that is gone once it finishes.
START_MARK_SCRIPT = Path('/usr/local/share/proxmenux/oci/engine/remote/oci_console_mark.sh')
START_MARK = '=== ProxMenux: container started ' START_MARK = '=== ProxMenux: container started '
def start_mark_hook(vmid: int) -> str: def start_mark_hook(vmid: int) -> str:
script = START_MARK_SCRIPT script = START_MARK_SCRIPT
# The hook runs before liblxc opens the console log, and liblxc refuses to
# start a container whose log directory is missing: on another cluster
# node, after a migration, it may never have been created.
# `test`, not `[`: a bracket in the configuration reads as a snapshot section. # `test`, not `[`: a bracket in the configuration reads as a snapshot section.
return f"lxc.hook.pre-start: /bin/sh -c 'test -x {script} && {script} {int(vmid)}; exit 0'" return (f"lxc.hook.pre-start: /bin/sh -c 'mkdir -p {LOG_DIR}; "
f"test -x {script} && {script} {int(vmid)}; exit 0'")
LOGROTATE = Path('/etc/logrotate.d/proxmenux-oci') LOGROTATE = Path('/etc/logrotate.d/proxmenux-oci')
# copytruncate, because liblxc keeps the file open for as long as the # copytruncate, because liblxc keeps the file open for as long as the
# container runs; moving it away would leave the application writing into the # container runs; moving it away would leave the application writing into the
+17 -5
View File
@@ -44,7 +44,17 @@ def tmpfs_lines(deployment):
return result return result
# /etc/pve/lxc is the folder of the local node only; this one is the same on
# every node of a cluster, so a migrated container still finds its include.
CLUSTER_DIR = Path('/etc/pve/proxmenux')
def include_path(vmid): def include_path(vmid):
return CLUSTER_DIR / f'{int(vmid)}.sysctls'
def legacy_include_path(vmid):
"""Where installations made before the cluster folder keep the include."""
return Path(f'/etc/pve/lxc/{int(vmid)}.proxmenux-sysctls') return Path(f'/etc/pve/lxc/{int(vmid)}.proxmenux-sysctls')
@@ -56,10 +66,11 @@ def check(config, deployment, vmid):
raise ValueError(translate('The tmpfs mounts of the container differ from the saved record')) raise ValueError(translate('The tmpfs mounts of the container differ from the saved record'))
includes = [line.split(': ',1)[1] for line in lines if line.startswith('lxc.include: ')] includes = [line.split(': ',1)[1] for line in lines if line.startswith('lxc.include: ')]
content = sysctl_content(deployment) content = sysctl_content(deployment)
if includes != ([str(include_path(vmid))] if content else []): allowed = [[str(include_path(vmid))], [str(legacy_include_path(vmid))]] if content else [[]]
if includes not in allowed:
raise ValueError(translate('The sysctl include is unknown or differs from the saved record')) raise ValueError(translate('The sysctl include is unknown or differs from the saved record'))
if content: if content:
path = include_path(vmid) path = Path(includes[0])
info = path.lstat() info = path.lstat()
if not stat.S_ISREG(info.st_mode) or info.st_uid != 0 or info.st_mode & 0o022: if not stat.S_ISREG(info.st_mode) or info.st_uid != 0 or info.st_mode & 0o022:
raise ValueError(translate('The sysctl include is not a safe host file')) raise ValueError(translate('The sysctl include is not a safe host file'))
@@ -82,8 +93,8 @@ def check_recovery(config, state):
if line.startswith('lxc.mount.entry: tmpfs ') and line.split(': ', 1)[1] not in permitted: if line.startswith('lxc.mount.entry: tmpfs ') and line.split(': ', 1)[1] not in permitted:
raise ValueError(translate('A tmpfs mount is not part of the journal; recovery blocked')) raise ValueError(translate('A tmpfs mount is not part of the journal; recovery blocked'))
if line.startswith('lxc.include: '): if line.startswith('lxc.include: '):
path = include_path(state['vmid']) path = Path(line.split(': ', 1)[1])
if line.split(': ', 1)[1] != str(path): if path not in (include_path(state['vmid']), legacy_include_path(state['vmid'])):
raise ValueError(translate('An include is not part of the journal; recovery blocked')) raise ValueError(translate('An include is not part of the journal; recovery blocked'))
contents = {sysctl_content(plan) for plan in plans} - {''} contents = {sysctl_content(plan) for plan in plans} - {''}
info = path.lstat() info = path.lstat()
@@ -99,6 +110,7 @@ def restore(deployment, vmid):
path = include_path(vmid) path = include_path(vmid)
if path.is_symlink(): if path.is_symlink():
raise ValueError(translate('The sysctl include is not restored over a symbolic link')) raise ValueError(translate('The sysctl include is not restored over a symbolic link'))
path.parent.mkdir(parents=True, exist_ok=True)
fd, temporary = tempfile.mkstemp(dir=path.parent, prefix='.oci-sysctl-') fd, temporary = tempfile.mkstemp(dir=path.parent, prefix='.oci-sysctl-')
try: try:
with os.fdopen(fd, 'w') as output: with os.fdopen(fd, 'w') as output:
@@ -107,7 +119,7 @@ def restore(deployment, vmid):
os.fsync(output.fileno()) os.fsync(output.fileno())
# pmxcfs uses fixed permissions; ordinary filesystem fixtures still # pmxcfs uses fixed permissions; ordinary filesystem fixtures still
# receive an explicit restrictive mode. # receive an explicit restrictive mode.
if path.parent != Path('/etc/pve/lxc'): if Path('/etc/pve') not in path.parents:
os.chmod(temporary, 0o640) os.chmod(temporary, 0o640)
os.replace(temporary, path) os.replace(temporary, path)
finally: finally:
+80
View File
@@ -0,0 +1,80 @@
"""A migrated container finds what it needs on any node of a cluster."""
from pathlib import Path
import sys
import tempfile
import unittest
from unittest.mock import patch
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / "remote"))
import oci_console
import oci_runtime_settings as runtime_settings
DEPLOYMENT = {"security": {"sysctls": [{"name": "net.ipv4.ip_unprivileged_port_start", "value": "0"}]}}
class StartHookTests(unittest.TestCase):
def test_hook_creates_the_log_directory_before_liblxc_opens_it(self):
hook = oci_console.start_mark_hook(101)
self.assertTrue(hook.startswith("lxc.hook.pre-start: /bin/sh -c 'mkdir -p /var/log/proxmenux/oci; "))
self.assertIn("test -x", hook)
self.assertTrue(hook.endswith("101; exit 0'"))
self.assertNotIn("[", hook)
def test_hook_runs_the_installed_engine_not_the_installer_copy(self):
# The installer runs from a temporary copy that is removed afterwards.
self.assertIn("test -x /usr/local/share/proxmenux/oci/engine/remote/oci_console_mark.sh && ",
oci_console.start_mark_hook(101))
self.assertTrue((ROOT / "remote/oci_console_mark.sh").is_file())
class SysctlIncludeTests(unittest.TestCase):
def setUp(self):
tmp = tempfile.TemporaryDirectory()
self.addCleanup(tmp.cleanup)
self.root = Path(tmp.name)
content = runtime_settings.sysctl_content(DEPLOYMENT)
self.new = self.root / "proxmenux/101.sysctls"
self.old = self.root / "lxc/101.proxmenux-sysctls"
for path in (self.new, self.old):
path.parent.mkdir(parents=True)
path.write_text(content)
path.chmod(0o640)
for name, value in (("include_path", lambda vmid: self.new), ("legacy_include_path", lambda vmid: self.old)):
patcher = patch.object(runtime_settings, name, value)
patcher.start()
self.addCleanup(patcher.stop)
def config(self, include):
return f"arch: amd64\nlxc.include: {include}\n".encode()
def test_cluster_path_and_the_path_of_earlier_installs_are_accepted(self):
runtime_settings.check(self.config(self.new), DEPLOYMENT, 101)
runtime_settings.check(self.config(self.old), DEPLOYMENT, 101)
def test_any_other_include_is_refused(self):
with self.assertRaises(ValueError):
runtime_settings.check(self.config(self.root / "elsewhere"), DEPLOYMENT, 101)
def test_recovery_accepts_both_paths_only(self):
state = {"vmid": 101, "record": {"deployment": DEPLOYMENT}}
runtime_settings.check_recovery(self.config(self.new), state)
runtime_settings.check_recovery(self.config(self.old), state)
with self.assertRaises(ValueError):
runtime_settings.check_recovery(self.config(self.root / "elsewhere"), state)
def test_restore_writes_the_cluster_path(self):
self.new.unlink()
self.new.parent.rmdir()
runtime_settings.restore(DEPLOYMENT, 101)
self.assertEqual(self.new.read_text(), runtime_settings.sysctl_content(DEPLOYMENT))
def test_the_cluster_folder_is_shared_by_every_node(self):
self.assertEqual(runtime_settings.CLUSTER_DIR, Path("/etc/pve/proxmenux"))
self.assertNotIn(Path("/etc/pve/lxc"), runtime_settings.CLUSTER_DIR.parents)
if __name__ == "__main__":
unittest.main()