Update build.func

This commit is contained in:
CanbiZ 2025-11-24 11:35:10 +01:00
parent cb2c3fab96
commit 7455f8195c

View File

@ -47,17 +47,7 @@ variables() {
METHOD="default" # sets the METHOD variable to "default", used for the API call. METHOD="default" # sets the METHOD variable to "default", used for the API call.
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable. RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)" # generates a random UUID and sets it to the RANDOM_UUID variable.
SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files SESSION_ID="${RANDOM_UUID:0:8}" # Short session ID (first 8 chars of UUID) for log files
BUILD_LOG="/tmp/create-lxc-${SESSION_ID}.log" # Host-side container creation log CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"}
CTTYPE="${CTTYPE:-${CT_TYPE:-1}}"
# Parse dev_mode early
parse_dev_mode
# Setup persistent log directory if logs mode active
if [[ "${DEV_MODE_LOGS:-false}" == "true" ]]; then
mkdir -p /var/log/community-scripts
BUILD_LOG="/var/log/community-scripts/create-lxc-${SESSION_ID}-$(date +%Y%m%d_%H%M%S).log"
fi
# Get Proxmox VE version and kernel version # Get Proxmox VE version and kernel version
if command -v pveversion >/dev/null 2>&1; then if command -v pveversion >/dev/null 2>&1; then
@ -535,35 +525,6 @@ base_settings() {
TAGS="community-script,${var_tags:-}" TAGS="community-script,${var_tags:-}"
ENABLE_FUSE=${var_fuse:-"${1:-no}"} ENABLE_FUSE=${var_fuse:-"${1:-no}"}
ENABLE_TUN=${var_tun:-"${1:-no}"} ENABLE_TUN=${var_tun:-"${1:-no}"}
ENABLE_NESTING=${var_nesting:-"${1:-1}"}
ENABLE_KEYCTL=${var_keyctl:-"${1:-0}"}
ALLOW_MOUNT_FS=${var_mount_fs:-""}
ENABLE_MKNOD=${var_mknod:-"${1:-0}"}
PROTECT_CT=${var_protection:-"${1:-no}"}
CT_TIMEZONE=${var_timezone:-""}
# Normalize feature flags to 0/1 immediately (pct requires numeric values, not yes/no)
# This must happen here before any usage of these variables
case "${ENABLE_NESTING,,}" in
yes | true) ENABLE_NESTING="1" ;;
no | false) ENABLE_NESTING="0" ;;
esac
case "${ENABLE_KEYCTL,,}" in
yes | true) ENABLE_KEYCTL="1" ;;
no | false) ENABLE_KEYCTL="0" ;;
esac
case "${ENABLE_MKNOD,,}" in
yes | true) ENABLE_MKNOD="1" ;;
no | false) ENABLE_MKNOD="0" ;;
esac
case "${ENABLE_FUSE,,}" in
yes | true) ENABLE_FUSE="1" ;;
no | false) ENABLE_FUSE="0" ;;
esac
case "${PROTECT_CT,,}" in
yes | true) PROTECT_CT="1" ;;
no | false) PROTECT_CT="0" ;;
esac
# Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts # Since these 2 are only defined outside of default_settings function, we add a temporary fallback. TODO: To align everything, we should add these as constant variables (e.g. OSTYPE and OSVERSION), but that would currently require updating the default_settings function for all existing scripts
if [ -z "$var_os" ]; then if [ -z "$var_os" ]; then
@ -587,9 +548,9 @@ default_var_settings() {
# Allowed var_* keys (alphabetically sorted) # Allowed var_* keys (alphabetically sorted)
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique) # Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
local VAR_WHITELIST=( local VAR_WHITELIST=(
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_keyctl var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu var_gateway var_hostname var_ipv6_method var_mac var_mtu
var_net var_nesting var_ns var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged var_net var_ns var_pw var_ram var_tags var_tun var_unprivileged
var_verbose var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_verbose var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage
) )
@ -667,14 +628,6 @@ var_ssh=no
# Features/Tags/verbosity # Features/Tags/verbosity
var_fuse=no var_fuse=no
var_tun=no var_tun=no
# Advanced Settings (Proxmox-official features)
var_nesting=1 # Allow nesting (required for Docker/LXC in CT)
var_keyctl=0 # Allow keyctl() - needed for Docker (systemd-networkd workaround)
var_mknod=0 # Allow device node creation (requires kernel 5.3+, experimental)
var_mount_fs= # Allow specific filesystems: nfs,fuse,ext4,etc (leave empty for defaults)
var_protection=no # Prevent accidental deletion of container
var_timezone= # Container timezone (e.g. Europe/Berlin, leave empty for host timezone)
var_tags=community-script var_tags=community-script
var_verbose=no var_verbose=no
@ -941,12 +894,6 @@ _build_current_app_vars_tmp() {
_apt_cacher_ip="${APT_CACHER_IP:-}" _apt_cacher_ip="${APT_CACHER_IP:-}"
_fuse="${ENABLE_FUSE:-no}" _fuse="${ENABLE_FUSE:-no}"
_tun="${ENABLE_TUN:-no}" _tun="${ENABLE_TUN:-no}"
_nesting="${ENABLE_NESTING:-1}"
_keyctl="${ENABLE_KEYCTL:-0}"
_mknod="${ENABLE_MKNOD:-0}"
_mount_fs="${ALLOW_MOUNT_FS:-}"
_protect="${PROTECT_CT:-no}"
_timezone="${CT_TIMEZONE:-}"
_tags="${TAGS:-}" _tags="${TAGS:-}"
_verbose="${VERBOSE:-no}" _verbose="${VERBOSE:-no}"
@ -990,12 +937,6 @@ _build_current_app_vars_tmp() {
[ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")" [ -n "$_fuse" ] && echo "var_fuse=$(_sanitize_value "$_fuse")"
[ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")" [ -n "$_tun" ] && echo "var_tun=$(_sanitize_value "$_tun")"
[ -n "$_nesting" ] && echo "var_nesting=$(_sanitize_value "$_nesting")"
[ -n "$_keyctl" ] && echo "var_keyctl=$(_sanitize_value "$_keyctl")"
[ -n "$_mknod" ] && echo "var_mknod=$(_sanitize_value "$_mknod")"
[ -n "$_mount_fs" ] && echo "var_mount_fs=$(_sanitize_value "$_mount_fs")"
[ -n "$_protect" ] && echo "var_protection=$(_sanitize_value "$_protect")"
[ -n "$_timezone" ] && echo "var_timezone=$(_sanitize_value "$_timezone")"
[ -n "$_tags" ] && echo "var_tags=$(_sanitize_value "$_tags")" [ -n "$_tags" ] && echo "var_tags=$(_sanitize_value "$_tags")"
[ -n "$_verbose" ] && echo "var_verbose=$(_sanitize_value "$_verbose")" [ -n "$_verbose" ] && echo "var_verbose=$(_sanitize_value "$_verbose")"
@ -1578,51 +1519,6 @@ advanced_settings() {
configure_ssh_settings configure_ssh_settings
export SSH_KEYS_FILE export SSH_KEYS_FILE
echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}" echo -e "${ROOTSSH}${BOLD}${DGN}Root SSH Access: ${BGN}$SSH${CL}"
# Advanced Settings - Proxmox Features
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS" --yesno "Configure Advanced Proxmox Features?" 10 58); then
# keyctl: for Docker support
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Enable keyctl()" --yesno "Allow keyctl() system calls?\n\nNeeded for: Docker inside container, systemd-networkd\nDefault: No (not needed for most applications)" 10 58); then
ENABLE_KEYCTL="1"
else
ENABLE_KEYCTL="0"
fi
echo -e "${SEARCH}${BOLD}${DGN}Allow keyctl(): ${BGN}$ENABLE_KEYCTL${CL}"
# mknod: device node creation
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Enable mknod()" --yesno "Allow device node creation?\n\nNeeded for: Complex device management (experimental, kernel 5.3+)\nDefault: No (rarely needed)" 10 58); then
ENABLE_MKNOD="1"
else
ENABLE_MKNOD="0"
fi
echo -e "${SEARCH}${BOLD}${DGN}Allow mknod(): ${BGN}$ENABLE_MKNOD${CL}"
# mount: specific filesystems
if MOUNT_FS=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allow specific filesystems (e.g., nfs,fuse,ext4)\nLeave blank for defaults" 8 58 "$ALLOW_MOUNT_FS" --title "Mount Filesystems" 3>&1 1>&2 2>&3); then
ALLOW_MOUNT_FS="$MOUNT_FS"
[ -z "$ALLOW_MOUNT_FS" ] && ALLOW_MOUNT_FS="(defaults)"
else
exit_script
fi
echo -e "${SEARCH}${BOLD}${DGN}Mount Filesystems: ${BGN}$ALLOW_MOUNT_FS${CL}"
# Container protection
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "Protection Flag" --yesno "Prevent accidental deletion?\n\nIf enabled, container cannot be deleted or its disk modified\nDefault: No" 10 58); then
PROTECT_CT="yes"
else
PROTECT_CT="no"
fi
echo -e "${SEARCH}${BOLD}${DGN}Container Protection: ${BGN}$PROTECT_CT${CL}"
# Container timezone
if CT_TIMEZONE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set container timezone (e.g., Europe/Berlin)\nLeave blank to use host timezone" 8 58 "$CT_TIMEZONE" --title "Container Timezone" 3>&1 1>&2 2>&3); then
[ -z "$CT_TIMEZONE" ] && CT_TIMEZONE="(host)"
else
exit_script
fi
echo -e "${SEARCH}${BOLD}${DGN}Container Timezone: ${BGN}$CT_TIMEZONE${CL}"
fi
if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then if (whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "FUSE Support" --yesno "Enable FUSE support?\nRequired for tools like rclone, mergerfs, AppImage, etc." 10 58); then
ENABLE_FUSE="yes" ENABLE_FUSE="yes"
else else
@ -1795,16 +1691,7 @@ install_script() {
fi fi
NEXTID=$(pvesh get /cluster/nextid) NEXTID=$(pvesh get /cluster/nextid)
# Get timezone using timedatectl (Debian 13+ compatible)
# Fallback to /etc/timezone for older systems
if command -v timedatectl >/dev/null 2>&1; then
timezone=$(timedatectl show --value --property=Timezone 2>/dev/null || echo "UTC")
elif [ -f /etc/timezone ]; then
timezone=$(cat /etc/timezone) timezone=$(cat /etc/timezone)
else
timezone="UTC"
fi
# Show APP Header # Show APP Header
header_info header_info
@ -1932,12 +1819,13 @@ settings_menu() {
local settings_items=( local settings_items=(
"1" "Manage API-Diagnostic Setting" "1" "Manage API-Diagnostic Setting"
"2" "Edit Default.vars" "2" "Edit Default.vars"
"3" "Edit Default Storage"
) )
if [ -f "$(get_app_defaults_path)" ]; then if [ -f "$(get_app_defaults_path)" ]; then
settings_items+=("3" "Edit App.vars for ${APP}") settings_items+=("4" "Edit App.vars for ${APP}")
settings_items+=("4" "Exit") settings_items+=("5" "Exit")
else else
settings_items+=("3" "Exit") settings_items+=("4" "Exit")
fi fi
local choice local choice
@ -2298,34 +2186,14 @@ build_container() {
none) ;; none) ;;
esac esac
# Build FEATURES array with advanced settings if [ "$CT_TYPE" == "1" ]; then
# Note: All feature flags are already normalized to 0/1 in default_settings() FEATURES="keyctl=1,nesting=1"
# Proxmox requires each feature as a separate parameter, not comma-separated string else
FEATURES_ARRAY=() FEATURES="nesting=1"
FEATURES_ARRAY+=("nesting=${ENABLE_NESTING}")
# keyctl: needed for Docker inside containers (systemd-networkd workaround)
# Typically needed for unprivileged containers with Docker
if [ "$CT_TYPE" == "1" ] || [ "$ENABLE_KEYCTL" == "1" ]; then
FEATURES_ARRAY+=("keyctl=1")
fi fi
# mknod: allow device node creation (requires kernel 5.3+, experimental) if [ "$ENABLE_FUSE" == "yes" ]; then
if [ "$ENABLE_MKNOD" == "1" ]; then FEATURES="$FEATURES,fuse=1"
FEATURES_ARRAY+=("mknod=1")
fi
# FUSE: required for rclone, mergerfs, AppImage, etc.
if [ "$ENABLE_FUSE" == "1" ]; then
FEATURES_ARRAY+=("fuse=1")
fi
# mount: allow specific filesystems (e.g., nfs, ext4, etc.)
# Format: mount=fstype1;fstype2;fstype3 (semicolon-separated, not comma!)
if [ -n "$ALLOW_MOUNT_FS" ]; then
# Replace commas with semicolons for proper pct syntax
ALLOW_MOUNT_FS_FORMATTED="${ALLOW_MOUNT_FS//,/;}"
FEATURES_ARRAY+=("mount=$ALLOW_MOUNT_FS_FORMATTED")
fi fi
TEMP_DIR=$(mktemp -d) TEMP_DIR=$(mktemp -d)
@ -2338,16 +2206,6 @@ build_container() {
export DIAGNOSTICS="$DIAGNOSTICS" export DIAGNOSTICS="$DIAGNOSTICS"
export RANDOM_UUID="$RANDOM_UUID" export RANDOM_UUID="$RANDOM_UUID"
export SESSION_ID="$SESSION_ID" export SESSION_ID="$SESSION_ID"
export BUILD_LOG="$BUILD_LOG"
export INSTALL_LOG="/root/.install-${SESSION_ID}.log"
export dev_mode="${dev_mode:-}"
export DEV_MODE_MOTD="${DEV_MODE_MOTD:-false}"
export DEV_MODE_KEEP="${DEV_MODE_KEEP:-false}"
export DEV_MODE_TRACE="${DEV_MODE_TRACE:-false}"
export DEV_MODE_PAUSE="${DEV_MODE_PAUSE:-false}"
export DEV_MODE_BREAKPOINT="${DEV_MODE_BREAKPOINT:-false}"
export DEV_MODE_LOGS="${DEV_MODE_LOGS:-false}"
export DEV_MODE_DRYRUN="${DEV_MODE_DRYRUN:-false}"
export CACHER="$APT_CACHER" export CACHER="$APT_CACHER"
export CACHER_IP="$APT_CACHER_IP" export CACHER_IP="$APT_CACHER_IP"
export tz="$timezone" export tz="$timezone"
@ -2361,59 +2219,22 @@ build_container() {
export CTTYPE="$CT_TYPE" export CTTYPE="$CT_TYPE"
export ENABLE_FUSE="$ENABLE_FUSE" export ENABLE_FUSE="$ENABLE_FUSE"
export ENABLE_TUN="$ENABLE_TUN" export ENABLE_TUN="$ENABLE_TUN"
export ENABLE_NESTING="$ENABLE_NESTING"
export ENABLE_KEYCTL="$ENABLE_KEYCTL"
export ENABLE_MKNOD="$ENABLE_MKNOD"
export ALLOW_MOUNT_FS="$ALLOW_MOUNT_FS"
export PROTECT_CT="$PROTECT_CT"
export CT_TIMEZONE="$CT_TIMEZONE"
export PCT_OSTYPE="$var_os" export PCT_OSTYPE="$var_os"
export PCT_OSVERSION="$var_version" export PCT_OSVERSION="$var_version"
export PCT_DISK_SIZE="$DISK_SIZE" export PCT_DISK_SIZE="$DISK_SIZE"
export PCT_OPTIONS="
# Build PCT_OPTIONS array (not string) for proper parameter handling -features $FEATURES
PCT_OPTIONS=() -hostname $HN
-tags $TAGS
# Add features - each as separate -features parameter $SD
for feature in "${FEATURES_ARRAY[@]}"; do $NS
PCT_OPTIONS+=("-features" "$feature") $NET_STRING
done -onboot 1
-cores $CORE_COUNT
PCT_OPTIONS+=("-hostname" "$HN") -memory $RAM_SIZE
PCT_OPTIONS+=("-tags" "$TAGS") -unprivileged $CT_TYPE
$PW
if [ -n "$SD" ]; then "
PCT_OPTIONS+=($SD) # Storage device flags (already formatted)
fi
if [ -n "$NS" ]; then
PCT_OPTIONS+=($NS) # Nameserver flags (already formatted)
fi
# Network configuration (single string with all network parameters)
PCT_OPTIONS+=($NET_STRING)
PCT_OPTIONS+=("-onboot" "1")
PCT_OPTIONS+=("-cores" "$CORE_COUNT")
PCT_OPTIONS+=("-memory" "$RAM_SIZE")
PCT_OPTIONS+=("-unprivileged" "$CT_TYPE")
# Protection flag
if [ "$PROTECT_CT" == "1" ]; then
PCT_OPTIONS+=("-protection" "1")
fi
# Timezone flag
if [ -n "$CT_TIMEZONE" ]; then
PCT_OPTIONS+=("-timezone" "$CT_TIMEZONE")
fi
# Password flag (already formatted as "-password xxx")
if [ -n "$PW" ]; then
PCT_OPTIONS+=($PW)
fi
export PCT_OPTIONS
export TEMPLATE_STORAGE="${var_template_storage:-}" export TEMPLATE_STORAGE="${var_template_storage:-}"
export CONTAINER_STORAGE="${var_container_storage:-}" export CONTAINER_STORAGE="${var_container_storage:-}"
create_lxc_container || exit $? create_lxc_container || exit $?
@ -2588,13 +2409,20 @@ EOF
[[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}") [[ "$selected_gpu" == "INTEL" ]] && devices=("${INTEL_DEVICES[@]}")
[[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}") [[ "$selected_gpu" == "AMD" ]] && devices=("${AMD_DEVICES[@]}")
# Use pct set to add devices with proper dev0/dev1 format # Add lxc.mount.entry for each device
# GIDs will be detected and set after container starts
local dev_index=0
for dev in "${devices[@]}"; do for dev in "${devices[@]}"; do
# Add to config using pct set (will be visible in GUI) echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG"
echo "dev${dev_index}: ${dev},gid=44" >>"$LXC_CONFIG"
dev_index=$((dev_index + 1)) if [[ "$CT_TYPE" == "0" ]]; then
# Privileged container - also add cgroup allows
local major minor
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
if [[ "$major" != "0" && "$minor" != "0" ]]; then
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
fi
fi
done done
export GPU_TYPE="$selected_gpu" export GPU_TYPE="$selected_gpu"
@ -2607,11 +2435,20 @@ EOF
return 0 return 0
fi fi
# Use pct set for NVIDIA devices # Add lxc.mount.entry for each NVIDIA device
local dev_index=0
for dev in "${NVIDIA_DEVICES[@]}"; do for dev in "${NVIDIA_DEVICES[@]}"; do
echo "dev${dev_index}: ${dev},gid=44" >>"$LXC_CONFIG" echo "lxc.mount.entry: $dev $dev none bind,optional,create=file" >>"$LXC_CONFIG"
dev_index=$((dev_index + 1))
if [[ "$CT_TYPE" == "0" ]]; then
# Privileged container - also add cgroup allows
local major minor
major=$(stat -c '%t' "$dev" 2>/dev/null || echo "0")
minor=$(stat -c '%T' "$dev" 2>/dev/null || echo "0")
if [[ "$major" != "0" && "$minor" != "0" ]]; then
echo "lxc.cgroup2.devices.allow: c $((0x$major)):$((0x$minor)) rwm" >>"$LXC_CONFIG"
fi
fi
done done
export GPU_TYPE="NVIDIA" export GPU_TYPE="NVIDIA"
@ -2723,9 +2560,7 @@ EOF'
fi fi
if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then if pct exec "$CTID" -- test -e "/usr/share/zoneinfo/$tz"; then
# Set timezone using symlink (Debian 13+ compatible) pct exec "$CTID" -- bash -c "tz='$tz'; echo \"\$tz\" >/etc/timezone && ln -sf \"/usr/share/zoneinfo/\$tz\" /etc/localtime"
# Create /etc/timezone for backwards compatibility with older scripts
pct exec "$CTID" -- bash -c "tz='$tz'; ln -sf \"/usr/share/zoneinfo/\$tz\" /etc/localtime && echo \"\$tz\" >/etc/timezone || true"
else else
msg_warn "Skipping timezone setup zone '$tz' not found in container" msg_warn "Skipping timezone setup zone '$tz' not found in container"
fi fi
@ -2741,121 +2576,14 @@ EOF'
# Install SSH keys # Install SSH keys
install_ssh_keys_into_ct install_ssh_keys_into_ct
# Dev mode: Setup MOTD/SSH AFTER network is ready and before installation
# This ensures the container is fully booted and accessible via SSH
if [[ "${DEV_MODE_MOTD:-false}" == "true" ]]; then
msg_dev "Setting up MOTD and SSH for debugging access"
pct exec "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)" <<'MOTD_SETUP'
# Only run motd_ssh function if it exists
if declare -f motd_ssh >/dev/null 2>&1; then
motd_ssh
else
msg_warn "motd_ssh function not found in ${var_install}.sh"
fi
MOTD_SETUP
msg_dev "MOTD/SSH ready - container accessible via SSH (IP: $ip_in_lxc)"
fi
# Run application installer # Run application installer
# NOTE: We disable error handling here because: if ! lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)"; then
# 1. Container errors are caught by error_handler INSIDE container local exit_code=$?
# 2. Container creates flag file with exit code # Try to copy installation log from container before exiting
# 3. We read flag file and handle cleanup manually below
# 4. We DON'T want host error_handler to fire for lxc-attach command itself
set +Eeuo pipefail # Disable ALL error handling temporarily
trap - ERR # Remove ERR trap completely
lxc-attach -n "$CTID" -- bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/install/${var_install}.sh)"
local lxc_exit=$?
set -Eeuo pipefail # Re-enable error handling
trap 'error_handler' ERR # Restore ERR trap
# Check for error flag file in container (more reliable than lxc-attach exit code)
local install_exit_code=0
if [[ -n "${SESSION_ID:-}" ]]; then
local error_flag="/root/.install-${SESSION_ID}.failed"
if pct exec "$CTID" -- test -f "$error_flag" 2>/dev/null; then
install_exit_code=$(pct exec "$CTID" -- cat "$error_flag" 2>/dev/null || echo "1")
pct exec "$CTID" -- rm -f "$error_flag" 2>/dev/null || true
fi
fi
# Fallback to lxc-attach exit code if no flag file
if [[ $install_exit_code -eq 0 && $lxc_exit -ne 0 ]]; then
install_exit_code=$lxc_exit
fi
# Installation failed?
if [[ $install_exit_code -ne 0 ]]; then
msg_error "Installation failed in container ${CTID} (exit code: ${install_exit_code})"
# Copy both logs from container before potential deletion
local build_log_copied=false
local install_log_copied=false
if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then if [[ -n "$CTID" && -n "${SESSION_ID:-}" ]]; then
# Copy BUILD_LOG (creation log) if it exists pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "/tmp/install-${SESSION_ID}.log" 2>/dev/null || true
if [[ -f "${BUILD_LOG}" ]]; then
cp "${BUILD_LOG}" "/tmp/create-lxc-${CTID}-${SESSION_ID}.log" 2>/dev/null && build_log_copied=true
fi fi
exit $exit_code
# Copy INSTALL_LOG from container
if pct pull "$CTID" "/root/.install-${SESSION_ID}.log" "/tmp/install-lxc-${CTID}-${SESSION_ID}.log" 2>/dev/null; then
install_log_copied=true
fi
# Show available logs
echo ""
[[ $build_log_copied == true ]] && echo -e "${GN}✔${CL} Container creation log: ${BL}/tmp/create-lxc-${CTID}-${SESSION_ID}.log${CL}"
[[ $install_log_copied == true ]] && echo -e "${GN}✔${CL} Installation log: ${BL}/tmp/install-lxc-${CTID}-${SESSION_ID}.log${CL}"
fi
# Dev mode: Keep container or open breakpoint shell
if [[ "${DEV_MODE_KEEP:-false}" == "true" ]]; then
msg_dev "Keep mode active - container ${CTID} preserved"
return 0
elif [[ "${DEV_MODE_BREAKPOINT:-false}" == "true" ]]; then
msg_dev "Breakpoint mode - opening shell in container ${CTID}"
echo -e "${YW}Type 'exit' to return to host${CL}"
pct enter "$CTID"
echo ""
echo -en "${YW}Container ${CTID} still running. Remove now? (y/N): ${CL}"
if read -r response && [[ "$response" =~ ^[Yy]$ ]]; then
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
msg_ok "Container ${CTID} removed"
else
msg_dev "Container ${CTID} kept for debugging"
fi
exit $install_exit_code
fi
# Prompt user for cleanup with 60s timeout (plain echo - no msg_info to avoid spinner)
echo ""
echo -en "${YW}Remove broken container ${CTID}? (Y/n) [auto-remove in 60s]: ${CL}"
if read -t 60 -r response; then
if [[ -z "$response" || "$response" =~ ^[Yy]$ ]]; then
# Remove container
echo -e "\n${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
elif [[ "$response" =~ ^[Nn]$ ]]; then
echo -e "\n${TAB}${YW}Container ${CTID} kept for debugging${CL}"
fi
else
# Timeout - auto-remove
echo -e "\n${YW}No response - auto-removing container${CL}"
echo -e "${TAB}${HOLD}${YW}Removing container ${CTID}${CL}"
pct stop "$CTID" &>/dev/null || true
pct destroy "$CTID" &>/dev/null || true
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
fi
exit $install_exit_code
fi fi
} }
@ -2937,40 +2665,79 @@ fix_gpu_gids() {
return 0 return 0
fi fi
# Silent operation to avoid spinner conflicts
msg_custom "🔧" "${BL}" "Detecting and setting correct GPU group IDs" msg_custom "🔧" "${BL}" "Detecting and setting correct GPU group IDs"
# Get actual GIDs from container # Ermittle die tatsächlichen GIDs aus dem Container
local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") local video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
local render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") local render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
# Create groups if they don't exist # Fallbacks wenn Gruppen nicht existieren
if [[ -z "$video_gid" ]]; then if [[ -z "$video_gid" ]]; then
pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true" >/dev/null 2>&1 # Versuche die video Gruppe zu erstellen
pct exec "$CTID" -- sh -c "groupadd -r video 2>/dev/null || true"
video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3") video_gid=$(pct exec "$CTID" -- sh -c "getent group video 2>/dev/null | cut -d: -f3")
[[ -z "$video_gid" ]] && video_gid="44" [[ -z "$video_gid" ]] && video_gid="44" # Ultimate fallback
fi fi
if [[ -z "$render_gid" ]]; then if [[ -z "$render_gid" ]]; then
pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true" >/dev/null 2>&1 # Versuche die render Gruppe zu erstellen
pct exec "$CTID" -- sh -c "groupadd -r render 2>/dev/null || true"
render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3") render_gid=$(pct exec "$CTID" -- sh -c "getent group render 2>/dev/null | cut -d: -f3")
[[ -z "$render_gid" ]] && render_gid="104" [[ -z "$render_gid" ]] && render_gid="104" # Ultimate fallback
fi fi
# Stop container to update config msg_custom "" "${DGN}" "Container GIDs detected - video:${video_gid}, render:${render_gid}"
# Prüfe ob die GIDs von den Defaults abweichen
local need_update=0
if [[ "$video_gid" != "44" ]] || [[ "$render_gid" != "104" ]]; then
need_update=1
fi
if [[ $need_update -eq 1 ]]; then
msg_custom "🔄" "${YW}" "Updating device GIDs in container config"
# Stoppe Container für Config-Update
pct stop "$CTID" >/dev/null 2>&1 pct stop "$CTID" >/dev/null 2>&1
sleep 1
# Update dev entries with correct GIDs # Update die dev Einträge mit korrekten GIDs
sed -i.bak -E "s|(dev[0-9]+: /dev/dri/renderD[0-9]+),gid=[0-9]+|\1,gid=${render_gid}|g" "$LXC_CONFIG" # Backup der Config
sed -i -E "s|(dev[0-9]+: /dev/dri/card[0-9]+),gid=[0-9]+|\1,gid=${video_gid}|g" "$LXC_CONFIG" cp "$LXC_CONFIG" "${LXC_CONFIG}.bak"
# Restart container # Parse und update jeden dev Eintrag
while IFS= read -r line; do
if [[ "$line" =~ ^dev[0-9]+: ]]; then
# Extract device path
local device_path=$(echo "$line" | sed -E 's/^dev[0-9]+: ([^,]+).*/\1/')
local dev_num=$(echo "$line" | sed -E 's/^(dev[0-9]+):.*/\1/')
if [[ "$device_path" =~ renderD ]]; then
# RenderD device - use render GID
echo "${dev_num}: ${device_path},gid=${render_gid}"
elif [[ "$device_path" =~ card ]]; then
# Card device - use video GID
echo "${dev_num}: ${device_path},gid=${video_gid}"
else
# Keep original line
echo "$line"
fi
else
# Keep non-dev lines
echo "$line"
fi
done <"$LXC_CONFIG" >"${LXC_CONFIG}.new"
mv "${LXC_CONFIG}.new" "$LXC_CONFIG"
# Starte Container wieder
pct start "$CTID" >/dev/null 2>&1 pct start "$CTID" >/dev/null 2>&1
sleep 2 sleep 3
msg_ok "GPU passthrough configured (video:${video_gid}, render:${render_gid})" msg_ok "Device GIDs updated successfully"
else
# For privileged containers: also fix permissions inside container msg_ok "Device GIDs are already correct"
fi
if [[ "$CT_TYPE" == "0" ]]; then if [[ "$CT_TYPE" == "0" ]]; then
pct exec "$CTID" -- bash -c " pct exec "$CTID" -- bash -c "
if [ -d /dev/dri ]; then if [ -d /dev/dri ]; then
@ -3136,7 +2903,7 @@ create_lxc_container() {
case "${_ans,,}" in case "${_ans,,}" in
y | yes) y | yes)
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)" msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
if $STD apt-get update && $STD apt-get install -y --only-upgrade pve-container lxc-pve; then if apt-get update -qq >/dev/null && apt-get install -y --only-upgrade pve-container lxc-pve >/dev/null; then
msg_ok "LXC stack upgraded." msg_ok "LXC stack upgraded."
if [[ "$do_retry" == "yes" ]]; then if [[ "$do_retry" == "yes" ]]; then
msg_info "Retrying container creation after upgrade" msg_info "Retrying container creation after upgrade"
@ -3581,13 +3348,13 @@ create_lxc_container() {
exit 211 exit 211
} }
LOGFILE="/tmp/pct_create_${CTID}_$(date +%Y%m%d_%H%M%S)_${SESSION_ID}.log" LOGFILE="/tmp/pct_create_${CTID}.log"
msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}"
msg_debug "Logfile: $LOGFILE" msg_debug "Logfile: $LOGFILE"
# First attempt # First attempt
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Validating template..." msg_error "Container creation failed on ${TEMPLATE_STORAGE}. Checking template..."
# Validate template file # Validate template file
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
@ -3606,48 +3373,49 @@ create_lxc_container() {
# Retry after repair # Retry after repair
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
# Fallback to local storage if not already on local # Fallback to local storage
if [[ "$TEMPLATE_STORAGE" != "local" ]]; then if [[ "$TEMPLATE_STORAGE" != "local" ]]; then
msg_info "Retrying container creation with fallback to local storage..." msg_warn "Retrying container creation with fallback to local storage..."
LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE" LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
msg_info "Downloading template to local..." msg_info "Downloading template to local..."
pveam download local "$TEMPLATE" >/dev/null 2>&1 pveam download local "$TEMPLATE" >/dev/null 2>&1
fi fi
if ! pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then if pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
# Local fallback also failed - check for LXC stack version issue
if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$?
case $rc in
0) : ;; # success - container created, continue
2)
echo "Upgrade was declined. Please update and re-run:
apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231
;;
3)
echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
exit 231
;;
esac
else
msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209
fi
else
msg_ok "Container successfully created using local fallback." msg_ok "Container successfully created using local fallback."
else
# --- Dynamic stack upgrade + auto-retry on the well-known error pattern ---
if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
echo "We can try to upgrade 'pve-container' and 'lxc-pve' now and retry automatically."
offer_lxc_stack_upgrade_and_maybe_retry "yes"
rc=$?
case $rc in
0) : ;; # success - container created, continue
2)
echo "Upgrade was declined. Please update and re-run:
apt update && apt install --only-upgrade pve-container lxc-pve"
exit 231
;;
3)
echo "Upgrade and/or retry failed. Please inspect: $LOGFILE"
exit 231
;;
esac
else
msg_error "Container creation failed even with local fallback. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x
bash -x -c "pct create $CTID local:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" 2>&1 | tee -a "$LOGFILE"
set +x
fi
exit 209
fi
fi fi
else else
# Already on local storage and still failed - check LXC stack version msg_error "Container creation failed on local storage. See $LOGFILE"
# --- Dynamic stack upgrade + auto-retry on the well-known error pattern ---
if grep -qiE 'unsupported .* version' "$LOGFILE"; then if grep -qiE 'unsupported .* version' "$LOGFILE"; then
echo echo
echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template." echo "pct reported 'unsupported ... version' your LXC stack might be too old for this template."
@ -3670,14 +3438,12 @@ create_lxc_container() {
msg_error "Container creation failed. See $LOGFILE" msg_error "Container creation failed. See $LOGFILE"
if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then if whiptail --yesno "pct create failed.\nDo you want to enable verbose debug mode and view detailed logs?" 12 70; then
set -x set -x
pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" 2>&1 | tee -a "$LOGFILE" bash -x -c "pct create $CTID local:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}" 2>&1 | tee -a "$LOGFILE"
set +x set +x
fi fi
exit 209 exit 209
fi fi
fi fi
else
msg_ok "Container successfully created after template repair."
fi fi
fi fi
@ -3694,9 +3460,6 @@ create_lxc_container() {
} }
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created." msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."
# Report container creation to API
post_to_api
} }
# ============================================================================== # ==============================================================================