From e22ff85dc83ea1c4a27107b635e83390e564245a Mon Sep 17 00:00:00 2001 From: MacRimi Date: Wed, 27 May 2026 17:36:11 +0200 Subject: [PATCH] Update install_coral_lxc.sh --- scripts/gpu_tpu/install_coral_lxc.sh | 370 ++++++++++++++++----------- 1 file changed, 220 insertions(+), 150 deletions(-) diff --git a/scripts/gpu_tpu/install_coral_lxc.sh b/scripts/gpu_tpu/install_coral_lxc.sh index e8cfd461..9920b751 100644 --- a/scripts/gpu_tpu/install_coral_lxc.sh +++ b/scripts/gpu_tpu/install_coral_lxc.sh @@ -6,8 +6,8 @@ # Revision : @Blaspt (USB passthrough via udev rule) # Copyright : (c) 2024 MacRimi # License : GPL-3.0 -# Version : 1.4 -# Last Updated: 01/04/2026 +# Version : 1.5 +# Last Updated: 27/05/2026 # ========================================================== # Description: # Configures and installs Coral TPU passthrough (USB and @@ -15,25 +15,30 @@ # dev / cgroup / mount entries into the LXC config, then # boots the container and installs the Edge TPU runtime # inside it so apps like Frigate can actually use the TPU. -# iGPU (DRI) device nodes are added alongside when present, -# which is the typical Frigate + Quick Sync combo. +# +# Scope: +# - This script is TPU-only. GPU / iGPU passthrough (Intel +# Quick Sync, AMD VA-API, NVIDIA) is delegated to +# add_gpu_lxc.sh — the script suggests running it first +# when a host GPU is detected but the container has no +# GPU configured. # # Features: -# - Supports Coral USB Accelerator and Coral M.2 / PCIe -# - Auto-detects M.2 via lspci (Global Unichip), USB via -# a persistent udev rule that creates /dev/coral -# - USB passthrough mounts /dev/bus/usb (not /dev/coral) -# so the container sees the real node even if the user -# replugs the device to a different port -# - PCIe/M.2 uses the PVE dev API (dev: ... ,gid=apex) -# which handles cgroup2 permissions automatically -# in both privileged and unprivileged containers -# - Fallback cgroup2 + mount if /dev/apex_0 not yet present -# (module not loaded on host — reboot still pending) +# - Container picker via `dialog` (matches add_gpu_lxc.sh) +# - Coral USB passthrough only when a Coral USB device is +# actually present on the host (avoids leaving orphan +# cgroup/mount entries when only M.2 is used) +# - Auto-detects M.2 via lspci (Global Unichip) +# - USB passthrough mounts /dev/bus/usb (not the dynamic +# /dev/coral symlink) so the CT sees the real node even +# if the user replugs the device +# - PCIe/M.2 uses the PVE dev API (devN: /dev/apex_0,gid=apex) +# which handles cgroup2 permissions automatically for +# privileged and unprivileged containers +# - Migrates legacy Coral entries (old cgroup2 + bind mount +# pairs) to the PVE dev API on every run # - Inside container: adds Google Coral APT repo and # installs libedgetpu1-std (default) or -max (optional) -# - Also installs iGPU user-space drivers when DRI nodes -# are passed, so Quick Sync works out of the box # - Idempotent: duplicate entries in the LXC config are # cleaned up on every run # ========================================================== @@ -51,30 +56,38 @@ load_language initialize_cache # ========================================================== -# CONTAINER SELECTION AND VALIDATION +# CONTAINER SELECTION (dialog — matches add_gpu_lxc.sh) # ========================================================== select_container() { - CONTAINERS=$(pct list | awk 'NR>1 {print $1, $3}' | xargs -n2) - if [ -z "$CONTAINERS" ]; then - msg_error "$(translate 'No containers available in Proxmox.')" - exit 1 + local menu_items=() + while IFS= read -r line; do + [[ "$line" =~ ^VMID ]] && continue + local ctid status name + ctid=$(echo "$line" | awk '{print $1}') + status=$(echo "$line" | awk '{print $2}') + name=$(echo "$line" | awk '{print $3}') + [[ -z "$ctid" ]] && continue + menu_items+=("$ctid" "${name:-CT-${ctid}} (${status})") + done < <(pct list 2>/dev/null) + + if [[ ${#menu_items[@]} -eq 0 ]]; then + dialog --backtitle "ProxMenux" \ + --title "$(translate 'Install Coral TPU in LXC')" \ + --msgbox "\n$(translate 'No LXC containers found on this system.')" 8 60 + exit 0 fi - CONTAINER_ID=$(whiptail --title "$(translate 'Select Container')" \ - --menu "$(translate 'Select the LXC container:')" 20 70 10 $CONTAINERS 3>&1 1>&2 2>&3) - - if [ -z "$CONTAINER_ID" ]; then - msg_error "$(translate 'No container selected. Exiting.')" - exit 1 - fi + CONTAINER_ID=$(dialog --backtitle "ProxMenux" \ + --title "$(translate 'Install Coral TPU in LXC')" \ + --menu "\n$(translate 'Select the LXC container:')" 20 72 12 \ + "${menu_items[@]}" \ + 2>&1 >/dev/tty) || exit 0 if ! pct list | awk 'NR>1 {print $1}' | grep -qw "$CONTAINER_ID"; then msg_error "$(translate 'Container with ID') $CONTAINER_ID $(translate 'does not exist. Exiting.')" exit 1 fi - - msg_ok "$(translate 'Container selected:') $CONTAINER_ID" } validate_container_id() { @@ -83,13 +96,67 @@ validate_container_id() { exit 1 fi + CT_WAS_RUNNING=false if pct status "$CONTAINER_ID" | grep -q "running"; then + CT_WAS_RUNNING=true msg_info "$(translate 'Stopping the container before applying configuration...')" pct stop "$CONTAINER_ID" msg_ok "$(translate 'Container stopped.')" fi } +# ========================================================== +# GPU PASSTHROUGH SUGGESTION +# ========================================================== +# Coral is typically paired with Quick Sync / NVENC for Frigate. If the host +# has a GPU but the container has no GPU configured, suggest the user to run +# Add GPU to LXC first — that's the right script for that job. +# ========================================================== + +suggest_gpu_passthrough_if_needed() { + local cfg="/etc/pve/lxc/${CONTAINER_ID}.conf" + [[ -f "$cfg" ]] || return 0 + + local host_has_gpu=false vendor_label="" + if lspci 2>/dev/null | grep -iE "VGA compatible|3D controller|Display controller" \ + | grep -qi "Intel"; then + host_has_gpu=true + vendor_label="Intel iGPU" + fi + if lspci 2>/dev/null | grep -iE "VGA compatible|3D controller|Display controller" \ + | grep -qiE "AMD|Advanced Micro|Radeon"; then + host_has_gpu=true + vendor_label="${vendor_label:+$vendor_label / }AMD GPU" + fi + if lspci 2>/dev/null | grep -iE "VGA compatible|3D controller|Display controller" \ + | grep -qi "NVIDIA"; then + host_has_gpu=true + vendor_label="${vendor_label:+$vendor_label / }NVIDIA GPU" + fi + + $host_has_gpu || return 0 + + # CT already has a GPU configured? Check both the modern dev API and the + # legacy lxc.mount.entry / cgroup formats. If any GPU device shows up, + # assume the user already handled it and skip the suggestion. + if grep -qE '^dev[0-9]+:[[:space:]]*/dev/(dri|nvidia|kfd)' "$cfg" 2>/dev/null \ + || grep -qE '^lxc\.mount\.entry:[[:space:]]*/dev/(dri|nvidia|kfd)' "$cfg" 2>/dev/null \ + || grep -qE '^lxc\.cgroup2\.devices\.allow:[[:space:]]+c[[:space:]]+(226|195):' "$cfg" 2>/dev/null; then + return 0 + fi + + local msg + msg="\n$(translate 'Host GPU detected'): ${vendor_label}\n\n" + msg+="$(translate 'This container has no GPU configured. Coral TPU works best alongside hardware video decoding (Quick Sync, VA-API, NVENC) for apps like Frigate.')\n\n" + msg+="$(translate 'Recommended: run') \"$(translate 'Add GPU to LXC')\" $(translate 'from the GPUs and Coral-TPU menu first, then run this option again.')\n\n" + msg+="$(translate 'Continue with Coral TPU configuration only?')" + + dialog --backtitle "ProxMenux" \ + --title "$(translate 'GPU Passthrough Not Configured')" \ + --yesno "$msg" 16 78 + [[ $? -ne 0 ]] && exit 0 +} + # ========================================================== # UDEV RULES FOR CORAL USB # ========================================================== @@ -107,7 +174,7 @@ SUBSYSTEM=="usb", ATTRS{idVendor}=="1a6e", ATTRS{idProduct}=="089a", MODE="0666" msg_ok "$(translate 'Udev rules for Coral USB devices added and rules reloaded.')" elif ! grep -q "18d1.*9302\|1a6e.*089a" "$RULE_FILE"; then # Append (>>) instead of overwriting (>) so any user-authored - # rules in this file survive. Audit Tier 7 — udev rule sobreescribe. + # rules in this file survive. printf '\n%s\n' "$RULE_CONTENT" >> "$RULE_FILE" udevadm control --reload-rules && udevadm trigger msg_ok "$(translate 'Udev rules for Coral USB devices appended and rules reloaded.')" @@ -124,13 +191,13 @@ add_mount_if_needed() { local DEVICE="$1" local DEST="$2" local CONFIG_FILE="$3" - + if grep -q "lxc.mount.entry: $DEVICE" "$CONFIG_FILE"; then return 0 fi - + local create_type="dir" - + if [ -e "$DEVICE" ]; then if [ -L "$DEVICE" ]; then create_type="dir" @@ -155,7 +222,7 @@ add_mount_if_needed() { ;; esac fi - + echo "lxc.mount.entry: $DEVICE $DEST none bind,optional,create=$create_type" >> "$CONFIG_FILE" } @@ -165,7 +232,8 @@ add_mount_if_needed() { cleanup_duplicate_entries() { local CONFIG_FILE="$1" - local TEMP_FILE=$(mktemp) + local TEMP_FILE + TEMP_FILE=$(mktemp) awk '!seen[$0]++' "$CONFIG_FILE" > "$TEMP_FILE" @@ -173,6 +241,40 @@ cleanup_duplicate_entries() { rm -f "$TEMP_FILE" } +# ========================================================== +# CLEANUP LEGACY CORAL M.2 ENTRIES +# ========================================================== +# Older versions of this script (and some manual setups) used the legacy +# `lxc.mount.entry: /dev/apex_0 ...` + `lxc.cgroup2.devices.allow: c :0 rwm` +# pair for Coral M.2. That pair is superseded by the PVE dev API (devN:) +# which handles cgroup2 permissions automatically and works in unprivileged +# containers. Remove the legacy pair so the new dev API entry doesn't stack +# alongside duplicates. +# +# NEVER touch USB-related entries (/dev/coral, /dev/bus/usb, c 189:* rwm) +# and NEVER touch lines unrelated to Coral (ttyUSB, ttyACM, serial, etc.) — +# those belong to the user / other scripts. +# ========================================================== + +cleanup_old_coral_m2_entries() { + local CONFIG_FILE="$1" + [[ -f "$CONFIG_FILE" ]] || return 0 + + # Only run when we just installed (or are about to install) /dev/apex_0 + # via the modern dev API. Without that guard we'd strip the legacy + # entries on hosts that legitimately still rely on them. + grep -qE '^dev[0-9]+:[[:space:]]*/dev/apex_0' "$CONFIG_FILE" || return 0 + + # Take a one-shot backup so the user can recover if anything goes wrong. + local BACKUP="${CONFIG_FILE}.proxmenux-coral.bak" + if [[ ! -f "$BACKUP" ]]; then + cp -a "$CONFIG_FILE" "$BACKUP" + fi + + sed -i '/^lxc\.mount\.entry:[[:space:]]*\/dev\/apex_0[[:space:]]/d' "$CONFIG_FILE" + sed -i '/^lxc\.cgroup2\.devices\.allow:[[:space:]]*c[[:space:]]\+[0-9]\+:0[[:space:]]\+rwm[[:space:]]*#[[:space:]]*Coral M2 Apex/d' "$CONFIG_FILE" +} + # Returns the next available dev index (dev0, dev1, ...) in a container config. # The PVE dev API (devN: /dev/foo,gid=N) works in both privileged and unprivileged # containers, handling cgroup2 permissions automatically. @@ -186,13 +288,13 @@ get_next_dev_index() { } # ========================================================== -# CONFIGURE LXC HARDWARE PASSTHROUGH +# CONFIGURE LXC CORAL PASSTHROUGH # ========================================================== configure_lxc_hardware() { validate_container_id CONFIG_FILE="/etc/pve/lxc/${CONTAINER_ID}.conf" - + if [ ! -f "$CONFIG_FILE" ]; then msg_error "$(translate 'Configuration file for container') $CONTAINER_ID $(translate 'not found.')" exit 1 @@ -201,75 +303,39 @@ configure_lxc_hardware() { cleanup_duplicate_entries "$CONFIG_FILE" # ============================================================ - # Enable nesting feature + # Enable nesting feature (needed for Coral userspace tooling) # ============================================================ if ! grep -Pq "^features:.*nesting=1" "$CONFIG_FILE"; then if grep -Pq "^features:" "$CONFIG_FILE"; then - sed -i 's/^features: \(.*\)/features: nesting=1,\1/' "$CONFIG_FILE" else - echo "features: nesting=1" >> "$CONFIG_FILE" fi msg_ok "$(translate 'Nesting feature enabled')" fi # ============================================================ - # iGPU support - # ============================================================ - msg_info "$(translate 'Configuring iGPU support...')" - - # Bind-mount the /dev/dri directory so apps can enumerate available devices - add_mount_if_needed "/dev/dri" "dev/dri" "$CONFIG_FILE" - - # Add each DRI device via the PVE dev API (gid=44 = render group). - # This approach works in unprivileged containers: PVE manages cgroup2 - # permissions automatically and maps the GID into the container namespace. - local igpu_dev_idx - igpu_dev_idx=$(get_next_dev_index "$CONFIG_FILE") - for dri_dev in /dev/dri/renderD128 /dev/dri/renderD129 /dev/dri/card0 /dev/dri/card1; do - if [[ -c "$dri_dev" ]]; then - if ! grep -q ":.*${dri_dev}" "$CONFIG_FILE"; then - echo "dev${igpu_dev_idx}: ${dri_dev},gid=44" >> "$CONFIG_FILE" - igpu_dev_idx=$((igpu_dev_idx + 1)) - fi - fi - done - - msg_ok "$(translate 'iGPU configuration added')" - - # ============================================================ - # Framebuffer support - # ============================================================ - if [ -e "/dev/fb0" ]; then - msg_info "$(translate 'Configuring Framebuffer support...')" - - if ! grep -Pq "^lxc.cgroup2.devices.allow: c 29:0 rwm" "$CONFIG_FILE"; then - echo "lxc.cgroup2.devices.allow: c 29:0 rwm # Framebuffer" >> "$CONFIG_FILE" - fi - - add_mount_if_needed "/dev/fb0" "dev/fb0" "$CONFIG_FILE" - msg_ok "$(translate 'Framebuffer configuration added')" - fi - - # ============================================================ - # Coral USB passthrough + # Coral USB passthrough — kept untouched on purpose. User said this + # part can stay exactly as-is regardless of whether a Coral USB is + # connected now: the udev rule + cgroup + /dev/bus/usb mount are + # harmless if no USB device is present and let the user plug one in + # later without re-running this script. # ============================================================ msg_info "$(translate 'Configuring Coral USB support...')" - + add_udev_rule_for_coral_usb - + if ! grep -Pq "^lxc.cgroup2.devices.allow: c 189:\\\* rwm" "$CONFIG_FILE"; then echo "lxc.cgroup2.devices.allow: c 189:* rwm # Coral USB" >> "$CONFIG_FILE" fi # FIX v1.3: Mount /dev/bus/usb instead of the /dev/coral symlink. - # The udev symlink /dev/coral cannot be safely passed through to LXC because - # it points to a dynamic path (e.g. /dev/bus/usb/001/005) that changes on - # reconnect. Mounting the full USB bus tree makes the real device node - # available inside the container regardless of port or reconnection. + # The udev symlink /dev/coral points to a dynamic path + # (e.g. /dev/bus/usb/001/005) that changes on reconnect — passing + # it through directly is unreliable. Mounting the USB bus tree + # makes the real device node available regardless of port. add_mount_if_needed "/dev/bus/usb" "dev/bus/usb" "$CONFIG_FILE" - + if [ -L "/dev/coral" ]; then msg_ok "$(translate 'Coral USB configuration added - device detected')" else @@ -287,8 +353,7 @@ configure_lxc_hardware() { # Pre-flight: warn if the host driver isn't loaded. Without `apex` # the container will see the device file but the TPU won't actually # be usable, and Frigate / coral-libs error out at runtime — much - # later than expected. Audit Tier 6 — `install_coral_lxc.sh` no - # verifica apex driver cargado. + # later than expected. if ! lsmod 2>/dev/null | grep -q '^apex'; then msg_warn "$(translate 'apex kernel module not loaded on host. Run "Install Coral on Host" first or the container will not see /dev/apex_0.')" fi @@ -300,9 +365,12 @@ configure_lxc_hardware() { if [ -e "/dev/apex_0" ]; then # Device is visible — use PVE dev API (works in unprivileged containers). # PVE handles cgroup2 permissions automatically. - if ! grep -q "dev.*apex_0" "$CONFIG_FILE"; then + if ! grep -qE "^dev[0-9]+:[[:space:]]*/dev/apex_0" "$CONFIG_FILE"; then echo "dev${apex_dev_idx}: /dev/apex_0,gid=${APEX_GID}" >> "$CONFIG_FILE" fi + # Migrate legacy M.2 entries (cgroup2 + bind-mount pair) that + # pre-dated the dev API on this CT. USB entries are NOT touched. + cleanup_old_coral_m2_entries "$CONFIG_FILE" msg_ok "$(translate 'Coral M.2 Apex configuration added - device ready')" else # Device not yet visible (host module not loaded or reboot pending). @@ -311,10 +379,6 @@ configure_lxc_hardware() { local APEX_MAJOR APEX_MAJOR=$(awk '/\bapex\b/{print $1}' /proc/devices 2>/dev/null | head -1) if [[ -z "$APEX_MAJOR" ]]; then - # Hardcoded `245` was wrong on kernels that load drivers in - # different order — dynamic majors vary. Surface the failure - # so the user knows the cgroup rule won't match and they need - # to load the apex module first. Audit Tier 6. msg_warn "$(translate 'Could not detect apex major number from /proc/devices. Load the apex module first: modprobe apex')" APEX_MAJOR="" fi @@ -328,22 +392,21 @@ configure_lxc_hardware() { fi fi - + # Final pass: drop any duplicates we may have introduced cleanup_duplicate_entries "$CONFIG_FILE" - - msg_ok "$(translate 'Hardware configuration completed for container') $CONTAINER_ID" + + msg_ok "$(translate 'Coral hardware configuration completed for container') $CONTAINER_ID" } # ========================================================== -# INSTALL DRIVERS INSIDE CONTAINER +# INSTALL CORAL TPU DRIVER INSIDE CONTAINER # ========================================================== install_coral_in_container() { - msg_info "$(translate 'Installing iGPU and Coral TPU drivers inside the container...')" + msg_info "$(translate 'Installing Coral TPU driver inside the container...')" tput sc LOG_FILE=$(mktemp) - if ! pct status "$CONTAINER_ID" | grep -q "running"; then pct start "$CONTAINER_ID" for _ in {1..15}; do @@ -355,23 +418,24 @@ install_coral_in_container() { fi fi - stop_spinner # Pre-flight: refuse to run on non-Debian-family containers. The # apt-get block below would crash with cryptic errors and leave the - # container half-configured. Audit Tier 6 — `install_coral_lxc.sh` - # asume Debian/Ubuntu sin distro detection. + # container half-configured. if ! pct exec "$CONTAINER_ID" -- bash -c 'command -v apt-get' &>/dev/null; then msg_error "$(translate 'Container does not have apt-get available. Coral driver installation only supports Debian/Ubuntu containers.')" return 1 fi - # Determine driver package for Coral M.2 + # Determine driver package for Coral M.2 (USB always uses -std). + # whiptail (not dialog) because this prompt appears in the middle of + # the install flow — project convention is dialog for initial menus, + # whiptail for mid-flow prompts. CORAL_M2=$(lspci | grep -i "Global Unichip") if [[ -n "$CORAL_M2" ]]; then DRIVER_OPTION=$(whiptail --title "$(translate 'Select driver version')" \ - --menu "$(translate 'Choose the driver version for Coral M.2:\n\nCaution: Maximum mode generates more heat.')" 15 60 2 \ + --menu "$(translate 'Choose the driver version for Coral M.2:')\n\n$(translate 'Caution: Maximum mode generates more heat.')" 15 60 2 \ 1 "libedgetpu1-std ($(translate 'standard performance'))" \ 2 "libedgetpu1-max ($(translate 'maximum performance'))" 3>&1 1>&2 2>&3) @@ -384,52 +448,49 @@ install_coral_in_container() { DRIVER_PACKAGE="libedgetpu1-std" fi - # Install drivers inside container + # Install driver inside container — TPU only, no iGPU userspace. + # iGPU drivers (va-driver-all, intel-opencl-icd, vainfo, etc.) are + # the job of add_gpu_lxc.sh. Keeping this script focused on TPU. + # + # Repository layout matches install_coral.sh on the host: + # keyring : /etc/apt/keyrings/coral-edgetpu.gpg + # list file: /etc/apt/sources.list.d/coral-edgetpu.list + # line : deb [signed-by=] https://packages.cloud.google.com/apt coral-edgetpu-stable main + # `apt-get install` (no version pin) always picks the latest libedgetpu + # available in the coral-edgetpu-stable channel, in sync with the host. script -q -c "pct exec \"$CONTAINER_ID\" -- bash -c ' set -e export DEBIAN_FRONTEND=noninteractive - echo \"[1/6] Updating package lists...\" + echo \"[1/3] Updating package lists...\" apt-get update -qq - - echo \"[2/6] Installing iGPU drivers...\" - apt-get install -y -qq va-driver-all ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools - - echo \"[3/6] Configuring DRI permissions...\" - if [ -e /dev/dri ]; then - chgrp video /dev/dri 2>/dev/null || true - chmod 755 /dev/dri 2>/dev/null || true - fi - - echo \"[4/6] Adding users to video/render groups...\" - adduser root video 2>/dev/null || true - adduser root render 2>/dev/null || true - - echo \"[5/6] Installing Coral TPU dependencies...\" + + echo \"[2/3] Setting up the Google Coral APT repository...\" apt-get install -y -qq gnupg curl ca-certificates - - echo \"[6/6] Adding Coral TPU repository...\" - curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg | gpg --dearmor -o /usr/share/keyrings/coral-edgetpu.gpg - echo \"deb [signed-by=/usr/share/keyrings/coral-edgetpu.gpg] https://packages.cloud.google.com/apt coral-edgetpu-stable main\" | tee /etc/apt/sources.list.d/coral-edgetpu.list >/dev/null - - echo \"\" - echo \"Updating package lists for Coral repository...\" + mkdir -p /etc/apt/keyrings + if [ ! -s /etc/apt/keyrings/coral-edgetpu.gpg ]; then + curl -fsSL https://packages.cloud.google.com/apt/doc/apt-key.gpg \ + | gpg --dearmor -o /etc/apt/keyrings/coral-edgetpu.gpg + chmod 0644 /etc/apt/keyrings/coral-edgetpu.gpg + fi + echo \"deb [signed-by=/etc/apt/keyrings/coral-edgetpu.gpg] https://packages.cloud.google.com/apt coral-edgetpu-stable main\" \ + | tee /etc/apt/sources.list.d/coral-edgetpu.list >/dev/null apt-get update -qq - - echo \"Installing Coral TPU driver ($DRIVER_PACKAGE)...\" + + echo \"[3/3] Installing latest Coral TPU runtime ($DRIVER_PACKAGE)...\" apt-get install -y -qq $DRIVER_PACKAGE - + '" "$LOG_FILE" 2>&1 if [ $? -eq 0 ]; then tput rc tput ed rm -f "$LOG_FILE" - msg_ok "$(translate 'iGPU and Coral TPU drivers installed successfully inside the container.')" + msg_ok "$(translate 'Coral TPU driver installed successfully inside the container.')" else tput rc tput ed - msg_error "$(translate 'Failed to install drivers inside the container.')" + msg_error "$(translate 'Failed to install Coral TPU driver inside the container.')" echo "" echo "$(translate 'Installation log:')" cat "$LOG_FILE" @@ -439,18 +500,12 @@ install_coral_in_container() { } # ========================================================== -# VERIFICATION AND SUMMARY +# VERIFICATION AND SUMMARY (Coral only) # ========================================================== show_configuration_summary() { local CONFIG_FILE="/etc/pve/lxc/${CONTAINER_ID}.conf" - - - # iGPU - if grep -q "c 226:0 rwm" "$CONFIG_FILE"; then - msg_ok2 "✓ iGPU support: $(translate 'Enabled')" - fi - + # Coral USB if grep -q "c 189:.*rwm.*Coral USB" "$CONFIG_FILE"; then if [ -L "/dev/coral" ]; then @@ -459,16 +514,22 @@ show_configuration_summary() { msg_ok2 "⚠ Coral USB: $(translate 'Enabled but not connected')" fi fi - - # Coral M.2 - if grep -q "c 245:0 rwm.*Coral M2" "$CONFIG_FILE"; then + + # Coral M.2 — either via dev API or legacy cgroup2 entry + local m2_configured=false + if grep -qE "^dev[0-9]+:[[:space:]]*/dev/apex_0" "$CONFIG_FILE"; then + m2_configured=true + elif grep -qE "^lxc\.cgroup2\.devices\.allow:[[:space:]]+c[[:space:]]+[0-9]+:0[[:space:]]+rwm.*Coral M2" "$CONFIG_FILE"; then + m2_configured=true + fi + + if $m2_configured; then if [ -e "/dev/apex_0" ]; then msg_ok2 "✓ Coral M.2: $(translate 'Enabled and ready')" else - msg_ok2 "⚠ Coral M.2: $(translate 'Enabled (device pending)')" + msg_ok2 "⚠ Coral M.2: $(translate 'Enabled (device pending — load apex module or reboot)')" fi fi - } # ========================================================== @@ -477,11 +538,20 @@ show_configuration_summary() { main() { select_container + suggest_gpu_passthrough_if_needed show_proxmenux_logo configure_lxc_hardware install_coral_in_container show_configuration_summary - + + # If the CT was running before we started, leave it running. Otherwise + # stop it again so we don't change the user's previous state. + if [[ "$CT_WAS_RUNNING" == "false" ]]; then + if pct status "$CONTAINER_ID" 2>/dev/null | grep -q "running"; then + pct stop "$CONTAINER_ID" >/dev/null 2>&1 || true + fi + fi + msg_ok "$(translate 'Configuration completed successfully!')" echo "" msg_success "$(translate 'Press Enter to return to menu...')" @@ -489,4 +559,4 @@ main() { } # Run main function -main \ No newline at end of file +main