Add build copy.func and update build.func

Added new 'build copy.func' script for LXC container build and configuration in Proxmox VE, including variable initialization, storage management, resource allocation, and advanced interactive configuration. Updated 'build.func' to support new features and improved logic for container setup, storage selection, and app-specific defaults management.
This commit is contained in:
CanbiZ 2025-11-24 09:34:35 +01:00
parent 6a2928ca47
commit f866c1cbef
2 changed files with 3918 additions and 133 deletions

3783
misc/build copy.func Normal file

File diff suppressed because it is too large Load Diff

View File

@ -542,29 +542,6 @@ base_settings() {
PROTECT_CT=${var_protection:-"${1:-no}"} PROTECT_CT=${var_protection:-"${1:-no}"}
CT_TIMEZONE=${var_timezone:-""} 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
var_os="debian" var_os="debian"
@ -1795,16 +1772,7 @@ install_script() {
fi fi
NEXTID=$(pvesh get /cluster/nextid) NEXTID=$(pvesh get /cluster/nextid)
timezone=$(cat /etc/timezone)
# 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)
else
timezone="UTC"
fi
# Show APP Header # Show APP Header
header_info header_info
@ -2298,26 +2266,24 @@ build_container() {
none) ;; none) ;;
esac esac
# Build FEATURES array with advanced settings # Build FEATURES string with advanced settings
# Note: All feature flags are already normalized to 0/1 in default_settings() # Start with nesting (almost always enabled for Proxmox CTs)
# Proxmox requires each feature as a separate parameter, not comma-separated string FEATURES="nesting=${ENABLE_NESTING}"
FEATURES_ARRAY=()
FEATURES_ARRAY+=("nesting=${ENABLE_NESTING}")
# keyctl: needed for Docker inside containers (systemd-networkd workaround) # keyctl: needed for Docker inside containers (systemd-networkd workaround)
# Typically needed for unprivileged containers with Docker # Typically needed for unprivileged containers with Docker
if [ "$CT_TYPE" == "1" ] || [ "$ENABLE_KEYCTL" == "1" ]; then if [ "$CT_TYPE" == "1" ] || [ "$ENABLE_KEYCTL" == "1" ]; then
FEATURES_ARRAY+=("keyctl=1") FEATURES="$FEATURES,keyctl=1"
fi fi
# mknod: allow device node creation (requires kernel 5.3+, experimental) # mknod: allow device node creation (requires kernel 5.3+, experimental)
if [ "$ENABLE_MKNOD" == "1" ]; then if [ "$ENABLE_MKNOD" == "1" ]; then
FEATURES_ARRAY+=("mknod=1") FEATURES="$FEATURES,mknod=1"
fi fi
# FUSE: required for rclone, mergerfs, AppImage, etc. # FUSE: required for rclone, mergerfs, AppImage, etc.
if [ "$ENABLE_FUSE" == "1" ]; then if [ "$ENABLE_FUSE" == "yes" ]; then
FEATURES_ARRAY+=("fuse=1") FEATURES="$FEATURES,fuse=1"
fi fi
# mount: allow specific filesystems (e.g., nfs, ext4, etc.) # mount: allow specific filesystems (e.g., nfs, ext4, etc.)
@ -2325,7 +2291,7 @@ build_container() {
if [ -n "$ALLOW_MOUNT_FS" ]; then if [ -n "$ALLOW_MOUNT_FS" ]; then
# Replace commas with semicolons for proper pct syntax # Replace commas with semicolons for proper pct syntax
ALLOW_MOUNT_FS_FORMATTED="${ALLOW_MOUNT_FS//,/;}" ALLOW_MOUNT_FS_FORMATTED="${ALLOW_MOUNT_FS//,/;}"
FEATURES_ARRAY+=("mount=$ALLOW_MOUNT_FS_FORMATTED") FEATURES="$FEATURES,mount=$ALLOW_MOUNT_FS_FORMATTED"
fi fi
TEMP_DIR=$(mktemp -d) TEMP_DIR=$(mktemp -d)
@ -2370,50 +2336,33 @@ build_container() {
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"
# Build protection flag if enabled
# Build PCT_OPTIONS array (not string) for proper parameter handling _PROT_FLAG=""
PCT_OPTIONS=() if [ "$PROTECT_CT" == "yes" ]; then
_PROT_FLAG="-protection 1"
# Add features - each as separate -features parameter
for feature in "${FEATURES_ARRAY[@]}"; do
PCT_OPTIONS+=("-features" "$feature")
done
PCT_OPTIONS+=("-hostname" "$HN")
PCT_OPTIONS+=("-tags" "$TAGS")
if [ -n "$SD" ]; then
PCT_OPTIONS+=($SD) # Storage device flags (already formatted)
fi fi
if [ -n "$NS" ]; then # Build timezone flag if set
PCT_OPTIONS+=($NS) # Nameserver flags (already formatted) _TZ_FLAG=""
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 if [ -n "$CT_TIMEZONE" ]; then
PCT_OPTIONS+=("-timezone" "$CT_TIMEZONE") _TZ_FLAG="-timezone $CT_TIMEZONE"
fi fi
# Password flag (already formatted as "-password xxx") export PCT_OPTIONS="
if [ -n "$PW" ]; then -features '$FEATURES'
PCT_OPTIONS+=($PW) -hostname $HN
fi -tags $TAGS
$SD
export PCT_OPTIONS $NS
$NET_STRING
-onboot 1
-cores $CORE_COUNT
-memory $RAM_SIZE
-unprivileged $CT_TYPE
$_PROT_FLAG
$_TZ_FLAG
$PW
"
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 +2537,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 +2563,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 +2688,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,6 +2704,21 @@ 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: # NOTE: We disable error handling here because:
# 1. Container errors are caught by error_handler INSIDE container # 1. Container errors are caught by error_handler INSIDE container
@ -2793,8 +2771,8 @@ EOF'
# Show available logs # Show available logs
echo "" echo ""
[[ "$build_log_copied" == true ]] && echo -e "${GN}✔${CL} Container creation log: ${BL}/tmp/create-lxc-${CTID}-${SESSION_ID}.log${CL}" [[ $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}" [[ $install_log_copied == true ]] && echo -e "${GN}✔${CL} Installation log: ${BL}/tmp/install-lxc-${CTID}-${SESSION_ID}.log${CL}"
fi fi
# Dev mode: Keep container or open breakpoint shell # Dev mode: Keep container or open breakpoint shell
@ -2830,18 +2808,6 @@ EOF'
echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}" echo -e "${BFR}${CM}${GN}Container ${CTID} removed${CL}"
elif [[ "$response" =~ ^[Nn]$ ]]; then elif [[ "$response" =~ ^[Nn]$ ]]; then
echo -e "\n${TAB}${YW}Container ${CTID} kept for debugging${CL}" echo -e "\n${TAB}${YW}Container ${CTID} kept for debugging${CL}"
# Dev mode: Setup MOTD/SSH for debugging access to broken container
# if [[ "${DEV_MODE_MOTD:-false}" == "true" ]]; then
# echo -e "${TAB}${HOLD}${DGN}Setting up MOTD and SSH for debugging...${CL}"
# if pct exec "$CTID" -- bash -c "
# source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/install.func)
# declare -f motd_ssh >/dev/null 2>&1 && motd_ssh || true
# " >/dev/null 2>&1; then
# local ct_ip=$(pct exec "$CTID" ip a s dev eth0 2>/dev/null | awk '/inet / {print $2}' | cut -d/ -f1)
# echo -e "${BFR}${CM}${GN}MOTD/SSH ready - SSH into container: ssh root@${ct_ip}${CL}"
# fi
# fi
fi fi
else else
# Timeout - auto-remove # Timeout - auto-remove
@ -2934,40 +2900,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}"
pct stop "$CTID" >/dev/null 2>&1
sleep 1
# Update dev entries with correct GIDs # Prüfe ob die GIDs von den Defaults abweichen
sed -i.bak -E "s|(dev[0-9]+: /dev/dri/renderD[0-9]+),gid=[0-9]+|\1,gid=${render_gid}|g" "$LXC_CONFIG" local need_update=0
sed -i -E "s|(dev[0-9]+: /dev/dri/card[0-9]+),gid=[0-9]+|\1,gid=${video_gid}|g" "$LXC_CONFIG" if [[ "$video_gid" != "44" ]] || [[ "$render_gid" != "104" ]]; then
need_update=1
fi
# Restart container if [[ $need_update -eq 1 ]]; then
pct start "$CTID" >/dev/null 2>&1 msg_custom "🔄" "${YW}" "Updating device GIDs in container config"
sleep 2
msg_ok "GPU passthrough configured (video:${video_gid}, render:${render_gid})" # Stoppe Container für Config-Update
pct stop "$CTID" >/dev/null 2>&1
# For privileged containers: also fix permissions inside container # Update die dev Einträge mit korrekten GIDs
# Backup der Config
cp "$LXC_CONFIG" "${LXC_CONFIG}.bak"
# 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
sleep 3
msg_ok "Device GIDs updated successfully"
else
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
@ -3133,7 +3138,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"
@ -3578,7 +3583,7 @@ 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"
@ -3635,7 +3640,7 @@ 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
@ -3667,7 +3672,7 @@ 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
@ -3691,9 +3696,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
} }
# ============================================================================== # ==============================================================================