update nstall_coral_pve9.sh

This commit is contained in:
MacRimi
2026-04-17 19:53:17 +02:00
parent e6faec24fa
commit 75c6f74fc4
6 changed files with 1003 additions and 240 deletions

View File

@@ -1,204 +0,0 @@
#!/bin/bash
# ==========================================================
# ProxMenux - A menu-driven script for Proxmox VE management
# ==========================================================
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
# Version : 1.1
# Last Updated: 17/08/2025
# ==========================================================
# Description:
# This script automates the process of enabling and configuring Intel Integrated GPU (iGPU) support in Proxmox VE LXC containers.
# Its goal is to simplify the configuration of hardware-accelerated graphical capabilities within containers, allowing for efficient
# use of Intel iGPUs for tasks such as transcoding, rendering, and accelerating graphics-intensive applications.
# ==========================================================
# Configuration ============================================
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
BASE_DIR="/usr/local/share/proxmenux"
UTILS_FILE="$BASE_DIR/utils.sh"
VENV_PATH="/opt/googletrans-env"
if [[ -f "$UTILS_FILE" ]]; then
source "$UTILS_FILE"
fi
load_language
initialize_cache
# ==========================================================
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
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
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() {
if [ -z "$CONTAINER_ID" ]; then
msg_error "$(translate 'Container ID not defined. Make sure to select a container first.')"
exit 1
fi
if pct status "$CONTAINER_ID" | grep -q "running"; then
msg_info "$(translate 'Stopping the container before applying configuration...')"
pct stop "$CONTAINER_ID"
msg_ok "$(translate 'Container stopped.')"
fi
}
configure_lxc_for_igpu() {
validate_container_id
CONFIG_FILE="/etc/pve/lxc/${CONTAINER_ID}.conf"
[[ -f "$CONFIG_FILE" ]] || { msg_error "$(translate 'Configuration file for container') $CONTAINER_ID $(translate 'not found.')"; exit 1; }
if [[ ! -d /dev/dri ]]; then
modprobe i915 2>/dev/null || true
for _ in {1..5}; do
[[ -d /dev/dri ]] && break
sleep 1
done
fi
CT_TYPE=$(pct config "$CONTAINER_ID" | awk '/^unprivileged:/ {print $2}')
[[ -z "$CT_TYPE" ]] && CT_TYPE="0"
msg_info "$(translate 'Configuring Intel iGPU passthrough for container...')"
for rn in /dev/dri/renderD*; do
[[ -e "$rn" ]] || continue
chmod 660 "$rn" 2>/dev/null || true
chgrp render "$rn" 2>/dev/null || true
done
mapfile -t RENDER_NODES < <(find /dev/dri -maxdepth 1 -type c -name 'renderD*' 2>/dev/null || true)
mapfile -t CARD_NODES < <(find /dev/dri -maxdepth 1 -type c -name 'card*' 2>/dev/null || true)
FB_NODE=""
[[ -e /dev/fb0 ]] && FB_NODE="/dev/fb0"
if [[ ${#RENDER_NODES[@]} -eq 0 && ${#CARD_NODES[@]} -eq 0 && -z "$FB_NODE" ]]; then
msg_warn "$(translate 'No VA-API devices found on host (/dev/dri*, /dev/fb0). Is i915 loaded?')"
return 0
fi
if grep -q '^features:' "$CONFIG_FILE"; then
grep -Eq '^features:.*(^|,)\s*nesting=1(\s|,|$)' "$CONFIG_FILE" || sed -i 's/^features:\s*/&nesting=1, /' "$CONFIG_FILE"
else
echo "features: nesting=1" >> "$CONFIG_FILE"
fi
if [[ "$CT_TYPE" == "0" ]]; then
sed -i '/^lxc\.cgroup2\.devices\.allow:\s*c\s*226:/d' "$CONFIG_FILE"
sed -i '\|^lxc\.mount\.entry:\s*/dev/dri|d' "$CONFIG_FILE"
sed -i '\|^lxc\.mount\.entry:\s*/dev/fb0|d' "$CONFIG_FILE"
echo "lxc.cgroup2.devices.allow: c 226:* rwm" >> "$CONFIG_FILE"
echo "lxc.mount.entry: /dev/dri dev/dri none bind,optional,create=dir" >> "$CONFIG_FILE"
[[ -n "$FB_NODE" ]] && echo "lxc.mount.entry: /dev/fb0 dev/fb0 none bind,optional,create=file" >> "$CONFIG_FILE"
else
sed -i '/^dev[0-9]\+:/d' "$CONFIG_FILE"
idx=0
for c in "${CARD_NODES[@]}"; do
echo "dev${idx}: $c,gid=44" >> "$CONFIG_FILE"
idx=$((idx+1))
done
for r in "${RENDER_NODES[@]}"; do
echo "dev${idx}: $r,gid=104" >> "$CONFIG_FILE"
idx=$((idx+1))
done
fi
msg_ok "$(translate 'iGPU configuration added to container') $CONTAINER_ID."
}
install_igpu_in_container() {
msg_info2 "$(translate 'Installing iGPU drivers inside the container...')"
tput sc
LOG_FILE=$(mktemp)
pct start "$CONTAINER_ID" >/dev/null 2>&1
script -q -c "pct exec \"$CONTAINER_ID\" -- bash -c '
set -e
getent group video >/dev/null || groupadd -g 44 video
getent group render >/dev/null || groupadd -g 104 render
usermod -aG video,render root || true
apt-get update >/dev/null 2>&1
apt-get install -y va-driver-all ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools
chgrp video /dev/dri 2>/dev/null || true
chmod 755 /dev/dri 2>/dev/null || true
'" "$LOG_FILE"
if [ $? -eq 0 ]; then
tput rc
tput ed
rm -f "$LOG_FILE"
msg_ok "$(translate 'iGPU drivers installed inside the container.')"
else
tput rc
tput ed
msg_error "$(translate 'Failed to install iGPU drivers inside the container.')"
cat "$LOG_FILE"
rm -f "$LOG_FILE"
exit 1
fi
}
select_container
show_proxmenux_logo
msg_title "$(translate "Add HW iGPU acceleration to an LXC")"
configure_lxc_for_igpu
install_igpu_in_container
msg_success "$(translate 'iGPU configuration completed in container') $CONTAINER_ID."
echo -e
msg_success "$(translate "Press Enter to return to menu...")"
read -r

View File

@@ -3,8 +3,8 @@
# =========================================
# Author : MacRimi
# License : MIT
# Version : 1.4 (kernel-conditional patches, direct DKMS, no debuild)
# Last Updated: 01/04/2026
# Version : 1.5 (feranick fork primary; kernel 6.12+ support; broken-pkg recovery)
# Last Updated: 17/04/2026
# =========================================
LOCAL_SCRIPTS="/usr/local/share/proxmenux/scripts"
@@ -72,6 +72,119 @@ pre_install_prompt() {
fi
}
# ============================================================
# Clean up a broken gasket-dkms package state.
#
# Context: if the user had gasket-dkms installed as a .deb (typical after
# following the Coral docs or via libedgetpu1-std's dependency chain), a
# kernel upgrade on PVE 9 triggers dkms autoinstall → compile fails on
# kernel 6.12+ → dpkg leaves the package half-configured. That broken state
# blocks further apt operations (including our own `apt-get install` below)
# with "E: Sub-process /usr/bin/dpkg returned an error code (1)".
# ============================================================
cleanup_broken_gasket_dkms() {
# dpkg status codes of interest (first column of `dpkg -l`):
# iF half-configured
# iU unpacked (not configured)
# iH half-installed
# Also catch the case where the package is installed but the DKMS source tree
# is broken (kernel upgrade without rebuild).
local pkg_state
pkg_state=$(dpkg -l gasket-dkms 2>/dev/null | awk '/^[a-zA-Z][a-zA-Z]/ {print $1}' | tail -1)
if [[ -z "$pkg_state" ]]; then
return 0 # package not present, nothing to clean
fi
# Any state other than "ii" (installed+configured cleanly) or "rc"
# (removed but config remaining) warrants proactive cleanup.
case "$pkg_state" in
ii|rc)
# Even when state is "ii", a stale DKMS module may exist — drop it to
# ensure our fresh build replaces the old one.
msg_info "$(translate 'Removing any pre-existing gasket-dkms package...')"
dpkg -r gasket-dkms >>"$LOG_FILE" 2>&1 || true
dkms remove gasket/1.0 --all >>"$LOG_FILE" 2>&1 || true
msg_ok "$(translate 'Pre-existing gasket-dkms package removed.')"
;;
*)
msg_warn "$(translate 'Detected broken gasket-dkms package state:') ${pkg_state}. $(translate 'Forcing removal...')"
dpkg --remove --force-remove-reinstreq gasket-dkms >>"$LOG_FILE" 2>&1 || true
dpkg --purge --force-all gasket-dkms >>"$LOG_FILE" 2>&1 || true
dkms remove gasket/1.0 --all >>"$LOG_FILE" 2>&1 || true
# apt-get install -f resolves any remaining dependency issues left by
# the forced removal above.
apt-get install -f -y >>"$LOG_FILE" 2>&1 || true
msg_ok "$(translate 'Broken gasket-dkms package state recovered.')"
;;
esac
}
# ============================================================
# Clone the gasket driver sources.
#
# Primary: feranick/gasket-driver — community fork, actively maintained,
# already carries patches for kernel
# 6.10 / 6.12 / 6.13. Preferred.
# Fallback: google/gasket-driver — upstream, stale. Requires the manual
# compatibility patches applied below.
#
# Sets GASKET_SOURCE_USED to "feranick" or "google" so downstream steps know
# whether to apply the local patches.
# ============================================================
clone_gasket_sources() {
local FERANICK_URL="https://github.com/feranick/gasket-driver.git"
local GOOGLE_URL="https://github.com/google/gasket-driver.git"
cd /tmp || exit 1
rm -rf gasket-driver >>"$LOG_FILE" 2>&1
msg_info "$(translate 'Cloning Coral driver repository (feranick fork)...')"
if git clone --depth=1 "$FERANICK_URL" gasket-driver >>"$LOG_FILE" 2>&1; then
GASKET_SOURCE_USED="feranick"
msg_ok "$(translate 'feranick/gasket-driver cloned (actively maintained, kernel 6.12+ ready).')"
return 0
fi
msg_warn "$(translate 'feranick fork unreachable. Falling back to google/gasket-driver...')"
rm -rf gasket-driver >>"$LOG_FILE" 2>&1
if git clone --depth=1 "$GOOGLE_URL" gasket-driver >>"$LOG_FILE" 2>&1; then
GASKET_SOURCE_USED="google"
msg_ok "$(translate 'google/gasket-driver cloned (fallback — will apply local patches).')"
return 0
fi
msg_error "$(translate 'Could not clone any gasket-driver repository. Check your internet connection and /tmp/coral_install.log')"
exit 1
}
# ============================================================
# On a failed DKMS build, surface the most relevant lines of make.log
# on-screen so the user (and bug reports) have immediate context without
# having to open the log file manually.
# ============================================================
show_dkms_build_failure() {
local make_log="/var/lib/dkms/gasket/1.0/build/make.log"
echo "" >&2
msg_warn "$(translate 'DKMS build failed. Last lines of make.log:')"
if [[ -f "$make_log" ]]; then
# Also append the full log to our install log for post-mortem.
{
echo "---- /var/lib/dkms/gasket/1.0/build/make.log ----"
cat "$make_log"
} >>"$LOG_FILE" 2>&1
tail -n 50 "$make_log" >&2
else
echo "$(translate '(make.log not found — DKMS may have failed before invoking make)')" >&2
fi
echo "" >&2
echo -e "${TAB}${BL}$(translate 'Full log:')${CL} /tmp/coral_install.log" >&2
echo "" >&2
}
install_coral_host() {
show_proxmenux_logo
: >"$LOG_FILE"
@@ -82,6 +195,9 @@ install_coral_host() {
KMAJ=$(echo "$KVER" | cut -d. -f1)
KMIN=$(echo "$KVER" | cut -d. -f2 | cut -d+ -f1 | cut -d- -f1)
# Recover from a broken gasket-dkms package state (typical after a kernel
# upgrade on PVE 9) before attempting any apt operations.
cleanup_broken_gasket_dkms
msg_info "$(translate 'Installing build dependencies...')"
export DEBIAN_FRONTEND=noninteractive
@@ -91,37 +207,39 @@ install_coral_host() {
fi
msg_ok "$(translate 'Build dependencies installed.')"
cd /tmp || exit 1
rm -rf gasket-driver >>"$LOG_FILE" 2>&1
msg_info "$(translate 'Cloning Google Coral driver repository...')"
if ! git clone https://github.com/google/gasket-driver.git >>"$LOG_FILE" 2>&1; then
msg_error "$(translate 'Could not clone the repository. Check /tmp/coral_install.log')"; exit 1
fi
msg_ok "$(translate 'Repository cloned successfully.')"
# Clone sources (feranick fork preferred, google fallback).
# Sets GASKET_SOURCE_USED.
clone_gasket_sources
cd /tmp/gasket-driver || exit 1
msg_info "$(translate 'Patching source for kernel compatibility...')"
# Patch 1: no_llseek was removed in kernel 6.5 — replace with noop_llseek
if [[ "$KMAJ" -gt 6 ]] || [[ "$KMAJ" -eq 6 && "$KMIN" -ge 5 ]]; then
sed -i 's/\.llseek = no_llseek/\.llseek = noop_llseek/' src/gasket_core.c
# Apply compatibility patches ONLY when using the stale google/gasket-driver
# fallback. feranick/gasket-driver already has equivalent fixes upstream, so
# re-applying them would double-edit (and in some cases break) the sources.
if [[ "$GASKET_SOURCE_USED" == "google" ]]; then
msg_info "$(translate 'Patching source for kernel compatibility...')"
# Patch 1: no_llseek was removed in kernel 6.5 — replace with noop_llseek
if [[ "$KMAJ" -gt 6 ]] || [[ "$KMAJ" -eq 6 && "$KMIN" -ge 5 ]]; then
sed -i 's/\.llseek = no_llseek/\.llseek = noop_llseek/' src/gasket_core.c
fi
# Patch 2: MODULE_IMPORT_NS changed to string-literal syntax in kernel 6.13.
# IMPORTANT: applying this patch on kernel < 6.13 causes a compile error.
if [[ "$KMAJ" -gt 6 ]] || [[ "$KMAJ" -eq 6 && "$KMIN" -ge 13 ]]; then
sed -i 's/^MODULE_IMPORT_NS(DMA_BUF);/MODULE_IMPORT_NS("DMA_BUF");/' src/gasket_page_table.c
fi
msg_ok "$(translate 'Source patched successfully.') (kernel ${KVER})"
else
msg_info2 "$(translate 'Skipping manual patches — feranick fork already supports this kernel.')"
fi
# Patch 2: MODULE_IMPORT_NS changed to string-literal syntax in kernel 6.13.
# IMPORTANT: applying this patch on kernel < 6.13 causes a compile error.
if [[ "$KMAJ" -gt 6 ]] || [[ "$KMAJ" -eq 6 && "$KMIN" -ge 13 ]]; then
sed -i 's/^MODULE_IMPORT_NS(DMA_BUF);/MODULE_IMPORT_NS("DMA_BUF");/' src/gasket_page_table.c
fi
msg_ok "$(translate 'Source patched successfully.') (kernel ${KVER})"
msg_info "$(translate 'Preparing DKMS source tree...')"
local GASKET_SRC="/usr/src/gasket-1.0"
# Remove any previous installation (package or manual) to avoid conflicts
dpkg -r gasket-dkms >>"$LOG_FILE" 2>&1 || true
# Remove any leftover manual DKMS tree from a previous run (package-level
# cleanup was already handled by cleanup_broken_gasket_dkms above).
dkms remove gasket/1.0 --all >>"$LOG_FILE" 2>&1 || true
rm -rf "$GASKET_SRC"
cp -r /tmp/gasket-driver/. "$GASKET_SRC"
@@ -133,13 +251,16 @@ install_coral_host() {
msg_info "$(translate 'Compiling Coral TPU drivers for current kernel...')"
if ! dkms build gasket/1.0 -k "$KVER" >>"$LOG_FILE" 2>&1; then
sed -n '1,200p' /var/lib/dkms/gasket/1.0/build/make.log >>"$LOG_FILE" 2>&1 || true
msg_error "$(translate 'DKMS build failed. Check /tmp/coral_install.log')"; exit 1
show_dkms_build_failure
msg_error "$(translate 'DKMS build failed.')"
exit 1
fi
if ! dkms install gasket/1.0 -k "$KVER" >>"$LOG_FILE" 2>&1; then
msg_error "$(translate 'DKMS install failed. Check /tmp/coral_install.log')"; exit 1
show_dkms_build_failure
msg_error "$(translate 'DKMS install failed.')"
exit 1
fi
msg_ok "$(translate 'Drivers compiled and installed via DKMS.')"
msg_ok "$(translate 'Drivers compiled and installed via DKMS.') (source: ${GASKET_SOURCE_USED})"
ensure_apex_group_and_udev

View File

@@ -520,6 +520,7 @@ unload_nvidia_modules() {
}
complete_nvidia_uninstall() {
msg_info "$(translate 'Completing NVIDIA uninstallation...')"
stop_and_disable_nvidia_services
unload_nvidia_modules