mirror of
https://github.com/community-scripts/ProxmoxVE-Local.git
synced 2026-08-03 10:58:46 -04:00
update build.func
This commit is contained in:
@@ -217,22 +217,16 @@ update_motd_ip() {
|
||||
# Only update if file exists and is from community-scripts
|
||||
if [ -f "$PROFILE_FILE" ] && grep -q "community-scripts" "$PROFILE_FILE" 2>/dev/null; then
|
||||
# Get current values
|
||||
local current_os="$(grep ^NAME /etc/os-release | cut -d= -f2 | tr -d '"') - Version: $(grep ^VERSION_ID /etc/os-release | cut -d= -f2 | tr -d '"')"
|
||||
local current_hostname="$(hostname)"
|
||||
local current_ip="$(hostname -I | awk '{print $1}')"
|
||||
|
||||
# Escape sed special chars in replacement strings (& \ |)
|
||||
current_os="${current_os//\\/\\\\}"
|
||||
current_os="${current_os//&/\\&}"
|
||||
current_hostname="${current_hostname//\\/\\\\}"
|
||||
current_hostname="${current_hostname//&/\\&}"
|
||||
current_ip="${current_ip//\\/\\\\}"
|
||||
current_ip="${current_ip//&/\\&}"
|
||||
|
||||
# Update only if values actually changed
|
||||
if ! grep -q "OS:.*$current_os" "$PROFILE_FILE" 2>/dev/null; then
|
||||
sed -i "s|OS:.*|OS: \${GN}$current_os\${CL}\\\"|" "$PROFILE_FILE"
|
||||
fi
|
||||
if ! grep -q "Hostname:.*$current_hostname" "$PROFILE_FILE" 2>/dev/null; then
|
||||
sed -i "s|Hostname:.*|Hostname: \${GN}$current_hostname\${CL}\\\"|" "$PROFILE_FILE"
|
||||
fi
|
||||
@@ -513,7 +507,7 @@ validate_bridge() {
|
||||
[[ -z "$bridge" ]] && return 1
|
||||
|
||||
# Check if bridge interface exists
|
||||
if ! ip link show "$bridge" &>/dev/null; then
|
||||
if ! ip link show dev "$bridge" &>/dev/null; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
@@ -979,7 +973,6 @@ base_settings() {
|
||||
fi
|
||||
|
||||
IPV6_METHOD=${var_ipv6_method:-"none"}
|
||||
IPV6_STATIC=${var_ipv6_static:-""}
|
||||
GATE=${var_gateway:-""}
|
||||
APT_CACHER=${var_apt_cacher:-""}
|
||||
APT_CACHER_IP=${var_apt_cacher_ip:-""}
|
||||
@@ -1015,8 +1008,12 @@ base_settings() {
|
||||
VLAN=${var_vlan:-""}
|
||||
SSH=${var_ssh:-"no"}
|
||||
SSH_AUTHORIZED_KEY=${var_ssh_authorized_key:-""}
|
||||
UDHCPC_FIX=${var_udhcpc_fix:-""}
|
||||
TAGS="community-script,${var_tags:-}"
|
||||
# Build TAGS: ensure community-script prefix, use semicolons (pct format), no duplicates
|
||||
if [[ "${var_tags:-}" == *community-script* ]]; then
|
||||
TAGS="${var_tags:-community-script}"
|
||||
else
|
||||
TAGS="community-script${var_tags:+;${var_tags}}"
|
||||
fi
|
||||
ENABLE_FUSE=${var_fuse:-"${1:-no}"}
|
||||
ENABLE_TUN=${var_tun:-"${1:-no}"}
|
||||
|
||||
@@ -1025,6 +1022,7 @@ base_settings() {
|
||||
ENABLE_NESTING=${var_nesting:-"1"}
|
||||
ENABLE_KEYCTL=${var_keyctl:-"0"}
|
||||
ENABLE_MKNOD=${var_mknod:-"0"}
|
||||
ALLOW_MOUNT_FS=${var_mount_fs:-""}
|
||||
PROTECT_CT=${var_protection:-"no"}
|
||||
CT_TIMEZONE=${var_timezone:-"$timezone"}
|
||||
[[ "${CT_TIMEZONE:-}" == Etc/* ]] && CT_TIMEZONE="host" # pct doesn't accept Etc/* zones
|
||||
@@ -1058,6 +1056,7 @@ load_vars_file() {
|
||||
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
|
||||
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
|
||||
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain
|
||||
var_post_install
|
||||
)
|
||||
|
||||
# Whitelist check helper
|
||||
@@ -1203,6 +1202,22 @@ load_vars_file() {
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_mknod)
|
||||
if [[ "$var_val" != "0" && "$var_val" != "1" ]]; then
|
||||
msg_warn "Invalid mknod value '$var_val' in $file (must be 0 or 1), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_mount_fs)
|
||||
# Normalize: strip spaces, trailing commas
|
||||
var_val="${var_val// /}"
|
||||
var_val="${var_val%%,}"
|
||||
var_val="${var_val##,}"
|
||||
if [[ -n "$var_val" ]] && [[ ! "$var_val" =~ ^[a-zA-Z0-9]+(,[a-zA-Z0-9]+)*$ ]]; then
|
||||
msg_warn "Invalid mount_fs value '$var_val' in $file (comma-separated fs names only, e.g. nfs,cifs), ignoring"
|
||||
continue
|
||||
fi
|
||||
;;
|
||||
var_ipv6_method)
|
||||
if [[ "$var_val" != "auto" && "$var_val" != "dhcp" && "$var_val" != "static" && "$var_val" != "none" ]]; then
|
||||
msg_warn "Invalid IPv6 method '$var_val' in $file (must be auto/dhcp/static/none), ignoring"
|
||||
@@ -1259,6 +1274,7 @@ default_var_settings() {
|
||||
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
|
||||
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
|
||||
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage
|
||||
var_post_install
|
||||
)
|
||||
|
||||
# Snapshot: environment variables (highest precedence)
|
||||
@@ -1354,6 +1370,11 @@ var_verbose=no
|
||||
# GitHub Personal Access Token (optional – avoids API rate limits during installs)
|
||||
# Create at https://github.com/settings/tokens – read-only public access is sufficient
|
||||
# var_github_token=ghp_your_token_here
|
||||
|
||||
# Optional post-install script (host-side path to a *.sh on the Proxmox host)
|
||||
# Runs ON THE HOST after the container is fully provisioned.
|
||||
# Available env vars: APP, NSAPP, CTID, IP, HN, STORAGE, BRG
|
||||
# var_post_install=/opt/post-install/myhook.sh
|
||||
EOF
|
||||
|
||||
# Now choose storages (always prompt unless just one exists)
|
||||
@@ -1428,10 +1449,11 @@ get_app_defaults_path() {
|
||||
if ! declare -p VAR_WHITELIST >/dev/null 2>&1; then
|
||||
# Note: Removed var_ctid (can only exist once), var_ipv6_static (static IPs are unique)
|
||||
declare -ag VAR_WHITELIST=(
|
||||
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu
|
||||
var_gateway var_hostname var_ipv6_method var_mac var_mtu
|
||||
var_net var_ns var_os var_pw var_ram var_tags var_tun var_unprivileged
|
||||
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage
|
||||
var_apt_cacher var_apt_cacher_ip var_brg var_cpu var_disk var_fuse var_github_token var_gpu var_keyctl
|
||||
var_gateway var_hostname var_ipv6_method var_mac var_mknod var_mount_fs var_mtu
|
||||
var_net var_nesting var_ns var_os var_protection var_pw var_ram var_tags var_timezone var_tun var_unprivileged
|
||||
var_verbose var_version var_vlan var_ssh var_ssh_authorized_key var_container_storage var_template_storage var_searchdomain
|
||||
var_post_install
|
||||
)
|
||||
fi
|
||||
|
||||
@@ -1644,6 +1666,7 @@ _build_current_app_vars_tmp() {
|
||||
|
||||
[ -n "$_tpl_storage" ] && echo "var_template_storage=$(_sanitize_value "$_tpl_storage")"
|
||||
[ -n "$_ct_storage" ] && echo "var_container_storage=$(_sanitize_value "$_ct_storage")"
|
||||
[ -n "${var_post_install:-}" ] && echo "var_post_install=$(_sanitize_value "${var_post_install}")"
|
||||
} >"$tmpf"
|
||||
|
||||
echo "$tmpf"
|
||||
@@ -1781,9 +1804,14 @@ advanced_settings() {
|
||||
trap 'tput rmcup 2>/dev/null || true' RETURN
|
||||
|
||||
# Initialize defaults
|
||||
TAGS="community-script;${var_tags:-}"
|
||||
# Build TAGS: ensure community-script prefix, use semicolons (pct format), no duplicates
|
||||
if [[ "${var_tags:-}" == *community-script* ]]; then
|
||||
TAGS="${var_tags:-community-script}"
|
||||
else
|
||||
TAGS="community-script${var_tags:+;${var_tags}}"
|
||||
fi
|
||||
local STEP=1
|
||||
local MAX_STEP=28
|
||||
local MAX_STEP=29
|
||||
|
||||
# Store values for back navigation - inherit from var_* app defaults
|
||||
local _ct_type="${var_unprivileged:-1}"
|
||||
@@ -1817,6 +1845,7 @@ advanced_settings() {
|
||||
local _enable_mknod="${var_mknod:-0}"
|
||||
local _mount_fs="${var_mount_fs:-}"
|
||||
local _protect_ct="${var_protection:-no}"
|
||||
local _post_install="${var_post_install:-}"
|
||||
|
||||
# Detect host timezone for default (if not set via var_timezone)
|
||||
local _host_timezone=""
|
||||
@@ -2518,6 +2547,13 @@ advanced_settings() {
|
||||
# STEP 22: Keyctl Support (Docker/systemd)
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
22)
|
||||
# Keyctl is always required for unprivileged containers — skip dialog
|
||||
if [[ "$_ct_type" == "1" ]]; then
|
||||
_enable_keyctl="1"
|
||||
((STEP++))
|
||||
continue
|
||||
fi
|
||||
|
||||
local keyctl_default_flag="--defaultno"
|
||||
[[ "$_enable_keyctl" == "1" ]] && keyctl_default_flag=""
|
||||
|
||||
@@ -2525,7 +2561,7 @@ advanced_settings() {
|
||||
--title "KEYCTL SUPPORT" \
|
||||
--ok-button "Next" --cancel-button "Back" \
|
||||
$keyctl_default_flag \
|
||||
--yesno "\nEnable Keyctl support?\n\nRequired for: Docker containers, systemd-networkd,\nand kernel keyring operations.\n\nNote: Automatically enabled for unprivileged containers.\n\n(App default: ${var_keyctl:-0})" 16 62; then
|
||||
--yesno "\nEnable Keyctl support?\n\nRequired for: Docker containers, systemd-networkd,\nand kernel keyring operations.\n\n(App default: ${var_keyctl:-0})" 14 62; then
|
||||
_enable_keyctl="1"
|
||||
else
|
||||
if [ $? -eq 1 ]; then
|
||||
@@ -2655,6 +2691,10 @@ advanced_settings() {
|
||||
--ok-button "Next" --cancel-button "Back" \
|
||||
--inputbox "\nAllow specific filesystem mounts.\n\nComma-separated list: nfs, cifs, fuse, ext4, etc.\nLeave empty for defaults (none).\n\nCurrent: $mount_hint" 14 62 "$_mount_fs" \
|
||||
3>&1 1>&2 2>&3); then
|
||||
# Normalize: strip spaces and trailing/leading commas
|
||||
result="${result// /}"
|
||||
result="${result%%,}"
|
||||
result="${result##,}"
|
||||
_mount_fs="$result"
|
||||
((STEP++))
|
||||
else
|
||||
@@ -2663,9 +2703,61 @@ advanced_settings() {
|
||||
;;
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# STEP 28: Verbose Mode & Confirmation
|
||||
# STEP 28: Optional host-side post-install hook (path on the Proxmox HOST)
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
28)
|
||||
local _hook_prompt="Optional: absolute path to a *.sh file ON THE PROXMOX HOST.
|
||||
|
||||
It runs as root on the HOST (NOT in the LXC) after the container
|
||||
is fully provisioned and started.
|
||||
|
||||
Available env vars: APP, NSAPP, CTID, IP, HN, STORAGE, BRG.
|
||||
|
||||
Leave empty to skip."
|
||||
while true; do
|
||||
if result=$(whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
|
||||
--title "POST-INSTALL HOOK (HOST)" \
|
||||
--ok-button "Next" --cancel-button "Back" \
|
||||
--inputbox "$_hook_prompt" 16 70 "${_post_install}" \
|
||||
3>&1 1>&2 2>&3); then
|
||||
# Normalize: strip surrounding whitespace
|
||||
result="$(printf '%s' "$result" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"
|
||||
if [[ -z "$result" ]]; then
|
||||
_post_install=""
|
||||
((STEP++))
|
||||
break
|
||||
fi
|
||||
# Reject obvious shell-meta sneaking through
|
||||
if [[ "$result" == *';'* || "$result" == *'$('* || "$result" == *'`'* || "$result" == *'&&'* || "$result" == *'||'* ]]; then
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID PATH" \
|
||||
--msgbox "Path contains shell metacharacters. Please provide a plain absolute file path." 10 70
|
||||
continue
|
||||
fi
|
||||
if [[ "$result" != /* ]]; then
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID PATH" \
|
||||
--msgbox "Path must be absolute (start with /).\n\nGot: $result" 10 70
|
||||
continue
|
||||
fi
|
||||
if [[ ! -f "$result" ]]; then
|
||||
if ! whiptail --backtitle "Proxmox VE Helper Scripts" --title "FILE NOT FOUND" \
|
||||
--yesno "File does not exist on host:\n\n$result\n\nKeep this path anyway?" 12 70; then
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
_post_install="$result"
|
||||
((STEP++))
|
||||
break
|
||||
else
|
||||
((STEP--))
|
||||
break
|
||||
fi
|
||||
done
|
||||
;;
|
||||
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
# STEP 29: Verbose Mode & Confirmation
|
||||
# ═══════════════════════════════════════════════════════════════════════════
|
||||
29)
|
||||
local verbose_default_flag="--defaultno"
|
||||
[[ "$_verbose" == "yes" ]] && verbose_default_flag=""
|
||||
|
||||
@@ -2694,6 +2786,11 @@ advanced_settings() {
|
||||
local apt_display="${_apt_cacher:-no}"
|
||||
[[ "$_apt_cacher" == "yes" && -n "$_apt_cacher_ip" ]] && apt_display="$_apt_cacher_ip"
|
||||
|
||||
local post_install_display="${_post_install:-(none)}"
|
||||
local post_install_warn=""
|
||||
[[ -n "$_post_install" ]] && post_install_warn="
|
||||
⚠ Hook runs as root on Proxmox HOST (not in LXC)"
|
||||
|
||||
local summary="Container Type: $ct_type_desc
|
||||
Container ID: $_ct_id
|
||||
Hostname: $_hostname
|
||||
@@ -2711,12 +2808,14 @@ Network:
|
||||
Features:
|
||||
FUSE: $_enable_fuse | TUN: $_enable_tun
|
||||
Nesting: $nesting_desc | Keyctl: $keyctl_desc
|
||||
Mknod: $([ "$_enable_mknod" == "1" ] && echo Enabled || echo Disabled) | Mount FS: ${_mount_fs:-(none)}
|
||||
GPU: $_enable_gpu | Protection: $protect_desc
|
||||
|
||||
Advanced:
|
||||
Timezone: $tz_display
|
||||
APT Cacher: $apt_display
|
||||
Verbose: $_verbose"
|
||||
Verbose: $_verbose
|
||||
Post-Install Script: ${post_install_display}${post_install_warn}"
|
||||
|
||||
if whiptail --backtitle "Proxmox VE Helper Scripts [Step $STEP/$MAX_STEP]" \
|
||||
--title "CONFIRM SETTINGS" \
|
||||
@@ -2759,6 +2858,7 @@ Advanced:
|
||||
APT_CACHER="$_apt_cacher"
|
||||
APT_CACHER_IP="$_apt_cacher_ip"
|
||||
VERBOSE="$_verbose"
|
||||
var_post_install="$_post_install"
|
||||
|
||||
# Update var_* based on user choice (for functions that check these)
|
||||
var_gpu="$_enable_gpu"
|
||||
@@ -2780,13 +2880,6 @@ Advanced:
|
||||
[[ -n "$_mac" ]] && MAC=",hwaddr=$_mac" || MAC=""
|
||||
[[ -n "$_vlan" ]] && VLAN=",tag=$_vlan" || VLAN=""
|
||||
|
||||
# Alpine UDHCPC fix
|
||||
if [ "$var_os" == "alpine" ] && [ "$NET" == "dhcp" ] && [ -n "$_ns" ]; then
|
||||
UDHCPC_FIX="yes"
|
||||
else
|
||||
UDHCPC_FIX="no"
|
||||
fi
|
||||
export UDHCPC_FIX
|
||||
export SSH_KEYS_FILE
|
||||
|
||||
# Exit alternate screen buffer before showing summary (so output remains visible)
|
||||
@@ -2811,6 +2904,8 @@ Advanced:
|
||||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Nesting: ${BGN}$([ "${ENABLE_NESTING:-1}" == "1" ] && echo "Enabled" || echo "Disabled")${CL}"
|
||||
[[ "${ENABLE_KEYCTL:-0}" == "1" ]] && echo -e "${CONTAINERTYPE}${BOLD}${DGN}Keyctl: ${BGN}Enabled${CL}"
|
||||
echo -e "${GPU}${BOLD}${DGN}GPU Passthrough: ${BGN}${ENABLE_GPU:-no}${CL}"
|
||||
[[ "${ENABLE_MKNOD:-0}" == "1" ]] && echo -e "${CONTAINERTYPE}${BOLD}${DGN}Mknod: ${BGN}Enabled${CL}"
|
||||
[[ -n "${ALLOW_MOUNT_FS:-}" ]] && echo -e "${CONTAINERTYPE}${BOLD}${DGN}Mount FS: ${BGN}${ALLOW_MOUNT_FS}${CL}"
|
||||
[[ "${PROTECT_CT:-no}" == "yes" || "${PROTECT_CT:-no}" == "1" ]] && echo -e "${CONTAINERTYPE}${BOLD}${DGN}Protection: ${BGN}Enabled${CL}"
|
||||
[[ -n "${CT_TIMEZONE:-}" ]] && echo -e "${INFO}${BOLD}${DGN}Timezone: ${BGN}$CT_TIMEZONE${CL}"
|
||||
[[ "$APT_CACHER" == "yes" ]] && echo -e "${INFO}${BOLD}${DGN}APT Cacher: ${BGN}$APT_CACHER_IP${CL}"
|
||||
@@ -2833,6 +2928,8 @@ Advanced:
|
||||
log_msg "IPv6: $IPV6_METHOD"
|
||||
log_msg "FUSE Support: ${ENABLE_FUSE:-no}"
|
||||
log_msg "Nesting: $([ "${ENABLE_NESTING:-1}" == "1" ] && echo "Enabled" || echo "Disabled")"
|
||||
log_msg "Mknod: $([ "${ENABLE_MKNOD:-0}" == "1" ] && echo "Enabled" || echo "Disabled")"
|
||||
[[ -n "${ALLOW_MOUNT_FS:-}" ]] && log_msg "Mount FS: ${ALLOW_MOUNT_FS}"
|
||||
log_msg "GPU Passthrough: ${ENABLE_GPU:-no}"
|
||||
log_msg "Verbose Mode: $VERBOSE"
|
||||
log_msg "Session ID: ${SESSION_ID}"
|
||||
@@ -3196,6 +3293,10 @@ check_container_resources() {
|
||||
if [[ "$current_ram" -lt "$var_ram" ]] || [[ "$current_cpu" -lt "$var_cpu" ]]; then
|
||||
msg_warn "Under-provisioned: Required ${var_cpu} CPU/${var_ram}MB RAM, Current ${current_cpu} CPU/${current_ram}MB RAM"
|
||||
echo -e "${YWB}Please ensure that the ${APP} LXC is configured with at least ${var_cpu} vCPU and ${var_ram} MB RAM for the build process.${CL}\n"
|
||||
if is_unattended; then
|
||||
msg_error "Aborted: under-provisioned LXC in unattended mode (${current_cpu} CPU/${current_ram}MB RAM < ${var_cpu} CPU/${var_ram}MB RAM)"
|
||||
exit 113
|
||||
fi
|
||||
echo -ne "${INFO}${HOLD} May cause data loss! ${INFO} Continue update with under-provisioned LXC? <yes/No> "
|
||||
read -r prompt </dev/tty
|
||||
if [[ ! ${prompt,,} =~ ^(yes)$ ]]; then
|
||||
@@ -3219,6 +3320,10 @@ check_container_storage() {
|
||||
usage=$((100 * used_size / total_size))
|
||||
if ((usage > 80)); then
|
||||
msg_warn "Storage is dangerously low (${usage}% used on /boot)"
|
||||
if is_unattended; then
|
||||
msg_error "Aborted: storage too low in unattended mode (${usage}% used on /boot)"
|
||||
exit 114
|
||||
fi
|
||||
echo -ne "Continue anyway? <y/N> "
|
||||
read -r prompt </dev/tty
|
||||
if [[ ! ${prompt,,} =~ ^(y|yes)$ ]]; then
|
||||
@@ -3470,6 +3575,52 @@ msg_menu() {
|
||||
return 0
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# run_addon_updates()
|
||||
#
|
||||
# - Scans /usr/local/bin/update_* for addon update scripts installed alongside
|
||||
# the main application (e.g. by tools/addon/*.sh)
|
||||
# - For each found addon, prompts the user (60s timeout, default no) whether
|
||||
# it should be updated as well
|
||||
# - Skipped entirely when PHS_SILENT=1 to keep unattended updates predictable
|
||||
# ------------------------------------------------------------------------------
|
||||
run_addon_updates() {
|
||||
shopt -s nullglob
|
||||
local addons=(/usr/local/bin/update_*)
|
||||
shopt -u nullglob
|
||||
|
||||
((${#addons[@]} == 0)) && return 0
|
||||
|
||||
if [[ "${PHS_SILENT:-0}" == "1" ]]; then
|
||||
msg_info "Detected ${#addons[@]} addon update script(s) - skipping (PHS_SILENT)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo
|
||||
echo -e "${INFO}${YW} Detected installed addon update script(s):${CL}"
|
||||
local a name
|
||||
for a in "${addons[@]}"; do
|
||||
echo -e "${TAB}- ${a##*/update_}"
|
||||
done
|
||||
echo
|
||||
|
||||
local ans
|
||||
for a in "${addons[@]}"; do
|
||||
name="${a##*/update_}"
|
||||
printf 'Do you also want to update addon "%s"? (y/N) [60s]: ' "$name"
|
||||
ans=""
|
||||
if read -r -t 60 ans; then :; else echo; fi
|
||||
case "${ans,,}" in
|
||||
y | yes)
|
||||
bash "$a" || msg_warn "Addon update for $name failed (rc=$?)"
|
||||
;;
|
||||
*)
|
||||
msg_info "Skipped addon: $name"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# start()
|
||||
#
|
||||
@@ -3479,7 +3630,7 @@ msg_menu() {
|
||||
# - Otherwise: shows update/setting menu and runs update_script with cleanup
|
||||
# ------------------------------------------------------------------------------
|
||||
start() {
|
||||
source "$(dirname "${BASH_SOURCE[0]}")/tools.func"
|
||||
source <(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/tools.func)
|
||||
if command -v pveversion >/dev/null 2>&1; then
|
||||
install_script || return 0
|
||||
return 0
|
||||
@@ -3489,6 +3640,17 @@ start() {
|
||||
ensure_profile_loaded
|
||||
get_lxc_ip
|
||||
update_script
|
||||
run_addon_updates
|
||||
update_motd_ip
|
||||
cleanup_lxc
|
||||
elif ! command -v whiptail &>/dev/null || ! [ -t 0 ] || [[ "$TERM" == "dumb" ]]; then
|
||||
msg_info "No interactive terminal detected – defaulting to silent update mode"
|
||||
VERBOSE="no"
|
||||
set_std_mode
|
||||
ensure_profile_loaded
|
||||
get_lxc_ip
|
||||
update_script
|
||||
run_addon_updates
|
||||
update_motd_ip
|
||||
cleanup_lxc
|
||||
else
|
||||
@@ -3517,6 +3679,7 @@ start() {
|
||||
ensure_profile_loaded
|
||||
get_lxc_ip
|
||||
update_script
|
||||
run_addon_updates
|
||||
update_motd_ip
|
||||
cleanup_lxc
|
||||
fi
|
||||
@@ -3553,13 +3716,7 @@ build_container() {
|
||||
fi
|
||||
|
||||
# IP (always required, default dhcp)
|
||||
# Guard against the literal word "static" being passed as the IP value –
|
||||
# that happens when var_net=static is exported without an actual address.
|
||||
if [[ "$NET" == "static" || -z "$NET" ]]; then
|
||||
msg_warn "NET value '${NET:-empty}' is not a valid IP/CIDR – falling back to dhcp"
|
||||
NET="dhcp"
|
||||
fi
|
||||
NET_STRING+=",ip=${NET}"
|
||||
NET_STRING+=",ip=${NET:-dhcp}"
|
||||
|
||||
# Gateway
|
||||
if [[ -n "$GATE" ]]; then
|
||||
@@ -3618,6 +3775,26 @@ build_container() {
|
||||
FEATURES="${FEATURES}fuse=1"
|
||||
fi
|
||||
|
||||
# Mknod support (user configurable via advanced settings)
|
||||
if [ "${ENABLE_MKNOD:-0}" == "1" ]; then
|
||||
[ -n "$FEATURES" ] && FEATURES="$FEATURES,"
|
||||
FEATURES="${FEATURES}mknod=1"
|
||||
fi
|
||||
|
||||
# Mount filesystem types (user configurable via advanced settings)
|
||||
if [ -n "${ALLOW_MOUNT_FS:-}" ]; then
|
||||
# Sanitize: strip spaces, trailing/leading commas, then convert commas to semicolons
|
||||
local _mount_clean="${ALLOW_MOUNT_FS// /}"
|
||||
_mount_clean="${_mount_clean%%,}"
|
||||
_mount_clean="${_mount_clean##,}"
|
||||
_mount_clean="${_mount_clean%%;}"
|
||||
_mount_clean="${_mount_clean//,/;}"
|
||||
if [ -n "$_mount_clean" ]; then
|
||||
[ -n "$FEATURES" ] && FEATURES="$FEATURES,"
|
||||
FEATURES="${FEATURES}mount=${_mount_clean}"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Build PCT_OPTIONS as string for export
|
||||
local _func_file
|
||||
local SCRIPT_DIR
|
||||
@@ -3649,7 +3826,7 @@ build_container() {
|
||||
export FUNCTIONS_FILE_PATH="$(curl -fsSL "$_func_url")"
|
||||
fi
|
||||
if [[ -z "$FUNCTIONS_FILE_PATH" || ${#FUNCTIONS_FILE_PATH} -lt 100 ]]; then
|
||||
msg_error "Failed to load install functions"
|
||||
msg_error "Failed to download install functions from: $_func_url"
|
||||
exit 115
|
||||
fi
|
||||
|
||||
@@ -5234,15 +5411,185 @@ create_lxc_container() {
|
||||
# Extract Debian OS minor from template name: debian-13-standard_13.1-1_amd64.tar.zst => "13.1"
|
||||
parse_template_osver() { sed -n 's/.*_\([0-9][0-9]*\(\.[0-9]\+\)\?\)-.*/\1/p' <<<"$1"; }
|
||||
|
||||
# Switch to the previous OS major version template and retry pct create
|
||||
# Determines the fallback version automatically based on available templates.
|
||||
# Returns: 0 = success, 1 = failed
|
||||
fallback_to_previous_os_version() {
|
||||
local old_template="$TEMPLATE"
|
||||
local os_type="${PCT_OSTYPE:-}"
|
||||
local current_ver="${PCT_OSVERSION:-}"
|
||||
|
||||
# Determine template search pattern based on OS type
|
||||
local tpl_pattern=""
|
||||
case "$os_type" in
|
||||
debian | ubuntu) tpl_pattern="-standard_" ;;
|
||||
alpine | fedora | rocky | centos) tpl_pattern="-default_" ;;
|
||||
*) tpl_pattern="" ;;
|
||||
esac
|
||||
|
||||
msg_info "Searching for an older $os_type template (current: $os_type $current_ver)"
|
||||
|
||||
# Collect all available versions for this OS type (local + online)
|
||||
local -a all_versions=()
|
||||
|
||||
# Local templates
|
||||
mapfile -t _local_vers < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v os="$os_type" -v pat="$tpl_pattern" '$1 ~ ("^"os"|/"os) && $1 ~ pat {print $1}' |
|
||||
sed 's|.*/||' |
|
||||
sed -E "s/^${os_type}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||
sort -u -V
|
||||
)
|
||||
all_versions+=("${_local_vers[@]}")
|
||||
|
||||
# Online templates (only if needed)
|
||||
if command -v timeout &>/dev/null; then
|
||||
timeout 30 pveam update >/dev/null 2>&1 || true
|
||||
else
|
||||
pveam update >/dev/null 2>&1 || true
|
||||
fi
|
||||
mapfile -t _online_vers < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
awk '{print $2}' |
|
||||
grep -E "^${os_type}-[0-9]" |
|
||||
{ [[ -n "$tpl_pattern" ]] && grep "$tpl_pattern" || cat; } |
|
||||
sed -E "s/^${os_type}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||
sort -u -V 2>/dev/null || true
|
||||
)
|
||||
all_versions+=("${_online_vers[@]}")
|
||||
|
||||
# Deduplicate and sort, find the highest version below current
|
||||
local fallback_ver=""
|
||||
fallback_ver=$(printf '%s\n' "${all_versions[@]}" | sort -u -V | awk -v cur="$current_ver" '{
|
||||
# Compare major versions: extract major part
|
||||
split($0, a, ".")
|
||||
split(cur, b, ".")
|
||||
if (a[1]+0 < b[1]+0) ver=$0
|
||||
} END { if (ver) print ver }')
|
||||
|
||||
if [[ -z "$fallback_ver" ]]; then
|
||||
msg_error "No older $os_type template version found."
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_ok "Fallback version: $os_type $fallback_ver"
|
||||
|
||||
# Find the actual template file for this version
|
||||
local fallback_search="${os_type}-${fallback_ver}"
|
||||
local fallback_template=""
|
||||
|
||||
# Check local first
|
||||
mapfile -t _fb_local < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v search="$fallback_search" -v pat="$tpl_pattern" '$1 ~ search && $1 ~ pat {print $1}' |
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
)
|
||||
if [[ ${#_fb_local[@]} -gt 0 ]]; then
|
||||
fallback_template="${_fb_local[-1]}"
|
||||
else
|
||||
# Check online
|
||||
mapfile -t _fb_online < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
awk '{print $2}' |
|
||||
grep -E "^${fallback_search}.*${tpl_pattern}" |
|
||||
sort -t - -k 2 -V 2>/dev/null || true
|
||||
)
|
||||
[[ ${#_fb_online[@]} -gt 0 ]] && fallback_template="${_fb_online[-1]}"
|
||||
fi
|
||||
|
||||
if [[ -z "$fallback_template" ]]; then
|
||||
msg_error "No template found for $os_type $fallback_ver."
|
||||
return 1
|
||||
fi
|
||||
|
||||
msg_ok "Found template: $fallback_template"
|
||||
|
||||
# Download if needed
|
||||
local fallback_path
|
||||
fallback_path="$(pvesm path "$TEMPLATE_STORAGE:vztmpl/$fallback_template" 2>/dev/null || true)"
|
||||
[[ -z "$fallback_path" ]] && fallback_path="/var/lib/vz/template/cache/$fallback_template"
|
||||
|
||||
if [[ ! -f "$fallback_path" ]]; then
|
||||
msg_info "Downloading $os_type $fallback_ver template"
|
||||
if ! pveam download "$TEMPLATE_STORAGE" "$fallback_template" >>"${BUILD_LOG:-/dev/null}" 2>&1; then
|
||||
msg_error "Failed to download $os_type $fallback_ver template."
|
||||
return 1
|
||||
fi
|
||||
msg_ok "Template downloaded"
|
||||
fi
|
||||
|
||||
# Update variables
|
||||
TEMPLATE="$fallback_template"
|
||||
TEMPLATE_PATH="$fallback_path"
|
||||
PCT_OSVERSION="$fallback_ver"
|
||||
export PCT_OSVERSION
|
||||
|
||||
# Retry pct create
|
||||
msg_info "Retrying container creation with $os_type $fallback_ver"
|
||||
if pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
|
||||
msg_ok "Container created successfully with $os_type $fallback_ver (fallback from $old_template)."
|
||||
return 0
|
||||
else
|
||||
msg_error "Container creation with $os_type $fallback_ver also failed. See $LOGFILE"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Offer upgrade for pve-container/lxc-pve if candidate > installed; optional auto-retry pct create
|
||||
# Returns:
|
||||
# 0 = no upgrade needed
|
||||
# 0 = no upgrade needed / container created after upgrade or explicit fallback
|
||||
# 1 = upgraded (and if do_retry=yes and retry succeeded, creation done)
|
||||
# 2 = user declined
|
||||
# 2 = user chose ignore
|
||||
# 3 = upgrade attempted but failed OR retry failed
|
||||
# 4 = user cancelled
|
||||
offer_lxc_stack_upgrade_and_maybe_retry() {
|
||||
local do_retry="${1:-no}" # yes|no
|
||||
local _pvec_i _pvec_c _lxcp_i _lxcp_c need=0
|
||||
local _ans
|
||||
|
||||
has_previous_os_version_template() {
|
||||
local os_type="${PCT_OSTYPE:-}"
|
||||
local current_ver="${PCT_OSVERSION:-}"
|
||||
local tpl_pattern="${TEMPLATE_PATTERN:-${TEMPLATE:-}}"
|
||||
local -a all_versions=()
|
||||
|
||||
[[ -n "$os_type" && -n "$current_ver" ]] || return 1
|
||||
|
||||
mapfile -t _local_vers < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk '{print $1}' |
|
||||
sed 's|.*/||' |
|
||||
grep -E "^${os_type}-[0-9]" |
|
||||
{ [[ -n "$tpl_pattern" ]] && grep "$tpl_pattern" || cat; } |
|
||||
sed -E "s/^${os_type}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||
sort -u -V
|
||||
)
|
||||
all_versions+=("${_local_vers[@]}")
|
||||
|
||||
if command -v timeout &>/dev/null; then
|
||||
timeout 30 pveam update >/dev/null 2>&1 || true
|
||||
else
|
||||
pveam update >/dev/null 2>&1 || true
|
||||
fi
|
||||
mapfile -t _online_vers < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
awk '{print $2}' |
|
||||
grep -E "^${os_type}-[0-9]" |
|
||||
{ [[ -n "$tpl_pattern" ]] && grep "$tpl_pattern" || cat; } |
|
||||
sed -E "s/^${os_type}-([0-9]+(\.[0-9]+)?).*/\1/" |
|
||||
sort -u -V 2>/dev/null || true
|
||||
)
|
||||
all_versions+=("${_online_vers[@]}")
|
||||
|
||||
printf '%s\n' "${all_versions[@]}" | sort -u -V | awk -v cur="$current_ver" '
|
||||
{
|
||||
split($0, a, ".")
|
||||
split(cur, b, ".")
|
||||
if (a[1]+0 < b[1]+0) found=1
|
||||
}
|
||||
END { exit found ? 0 : 1 }
|
||||
'
|
||||
}
|
||||
|
||||
_pvec_i="$(pkg_ver pve-container)"
|
||||
_lxcp_i="$(pkg_ver lxc-pve)"
|
||||
@@ -5263,14 +5610,78 @@ create_lxc_container() {
|
||||
msg_warn "An update for the Proxmox LXC stack is available"
|
||||
echo " pve-container: installed=${_pvec_i:-n/a} candidate=${_pvec_c:-n/a}"
|
||||
echo " lxc-pve : installed=${_lxcp_i:-n/a} candidate=${_lxcp_c:-n/a}"
|
||||
echo " note : option 1 runs host apt update + apt upgrade"
|
||||
echo
|
||||
read -rp "Do you want to upgrade now? [y/N] " _ans </dev/tty
|
||||
|
||||
# Offer older OS version fallback when template version might be too new for LXC stack
|
||||
local _has_fallback_option=false
|
||||
if [[ "$do_retry" == "yes" ]] && has_previous_os_version_template; then
|
||||
_has_fallback_option=true
|
||||
echo " [1] Run host upgrade now (recommended). WARNING: this runs apt upgrade and updates all Packages on your host!"
|
||||
echo " [2] Use an older ${PCT_OSTYPE} template instead (may not work with all scripts)"
|
||||
echo " [3] Ignore"
|
||||
echo " [4] Cancel"
|
||||
echo
|
||||
read -rp "Select option [1/2/3/4]: " _ans </dev/tty
|
||||
else
|
||||
echo " [1] Run host upgrade now (recommended). WARNING: this runs apt upgrade and updates all Packages on your host!"
|
||||
echo " [2] Ignore"
|
||||
echo " [3] Cancel"
|
||||
echo
|
||||
read -rp "Select option [1/2/3]: " _ans </dev/tty
|
||||
fi
|
||||
|
||||
if [[ "$_has_fallback_option" == true ]]; then
|
||||
case "$_ans" in
|
||||
1)
|
||||
_ans="y"
|
||||
;;
|
||||
2)
|
||||
if fallback_to_previous_os_version; then
|
||||
return 0
|
||||
else
|
||||
return 3
|
||||
fi
|
||||
;;
|
||||
3)
|
||||
return 2
|
||||
;;
|
||||
4)
|
||||
return 4
|
||||
;;
|
||||
*)
|
||||
return 4
|
||||
;;
|
||||
esac
|
||||
else
|
||||
case "$_ans" in
|
||||
1)
|
||||
_ans="y"
|
||||
;;
|
||||
2)
|
||||
return 2
|
||||
;;
|
||||
*)
|
||||
return 4
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
case "${_ans,,}" in
|
||||
y | yes)
|
||||
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
|
||||
msg_info "Running host upgrade for LXC stack compatibility"
|
||||
apt_update_safe
|
||||
if $STD apt-get install -y --only-upgrade pve-container lxc-pve; then
|
||||
if $STD apt-get upgrade -y; then
|
||||
msg_ok "LXC stack upgraded."
|
||||
# Verify pct binary still works after upgrade (partial upgrades can break Perl modules)
|
||||
if ! pct list &>/dev/null; then
|
||||
msg_error "LXC stack upgrade caused PVE tool breakage (likely Perl module incompatibility)."
|
||||
msg_custom "⚠️" "${YW}" "A partial package upgrade has left the PVE stack in an inconsistent state."
|
||||
msg_custom "🔧" "${YW}" "Please run the following on the Proxmox host, then retry:"
|
||||
echo -e "${TAB} apt update && apt upgrade -y"
|
||||
echo -e "${TAB} reboot"
|
||||
return 3
|
||||
fi
|
||||
if [[ "$do_retry" == "yes" ]]; then
|
||||
msg_info "Retrying container creation after upgrade"
|
||||
if pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >>"$LOGFILE" 2>&1; then
|
||||
@@ -5369,10 +5780,35 @@ create_lxc_container() {
|
||||
fi
|
||||
|
||||
msg_info "Validating storage '$CONTAINER_STORAGE'"
|
||||
STORAGE_TYPE=$(grep -E "^[^:]+: $CONTAINER_STORAGE$" /etc/pve/storage.cfg | cut -d: -f1 | head -1 || true)
|
||||
# Check if storage.cfg is accessible (pmxcfs must be mounted)
|
||||
if [[ ! -f /etc/pve/storage.cfg ]]; then
|
||||
if ! mountpoint -q /etc/pve 2>/dev/null; then
|
||||
msg_error "Proxmox cluster filesystem (pmxcfs) is not mounted at /etc/pve."
|
||||
msg_custom "🔧" "${YW}" "Try: systemctl restart pve-cluster"
|
||||
else
|
||||
msg_error "/etc/pve/storage.cfg does not exist."
|
||||
msg_custom "🔧" "${YW}" "Check Proxmox cluster filesystem integrity: pvecm status"
|
||||
fi
|
||||
exit 213
|
||||
fi
|
||||
|
||||
STORAGE_TYPE=$(grep -E "^[^:]+:[[:space:]]*$CONTAINER_STORAGE[[:space:]]*$" /etc/pve/storage.cfg | cut -d: -f1 | head -1 || true)
|
||||
|
||||
# Fallback: use pvesm status to determine storage type
|
||||
if [[ -z "$STORAGE_TYPE" ]]; then
|
||||
STORAGE_TYPE=$(pvesm status -storage "$CONTAINER_STORAGE" 2>/dev/null | awk 'NR>1{print $2}')
|
||||
fi
|
||||
|
||||
if [[ -z "$STORAGE_TYPE" ]]; then
|
||||
msg_error "Storage '$CONTAINER_STORAGE' not found in /etc/pve/storage.cfg"
|
||||
msg_custom "📋" "${YW}" "Available storages: $(pvesm status 2>/dev/null | awk 'NR>1{printf "%s (%s) ", $1, $2}' || echo 'n/a')"
|
||||
if [[ -r /etc/pve/storage.cfg ]]; then
|
||||
msg_custom "📋" "${YW}" "Storage definitions found in config:"
|
||||
grep -E '^[a-z]+:' /etc/pve/storage.cfg 2>/dev/null | while IFS= read -r _line; do
|
||||
echo "${TAB} $_line"
|
||||
done
|
||||
fi
|
||||
msg_custom "📖" "${YW}" "See https://pve.proxmox.com/wiki/Storage for storage configuration details."
|
||||
exit 213
|
||||
fi
|
||||
|
||||
@@ -5403,6 +5839,10 @@ create_lxc_container() {
|
||||
|
||||
if ! pvesm status -content rootdir 2>/dev/null | awk 'NR>1{print $1}' | grep -qx "$CONTAINER_STORAGE"; then
|
||||
msg_error "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) does not support 'rootdir' content."
|
||||
msg_custom "💡" "${YW}" "Enable 'Disk image' (rootdir) for storage '${CONTAINER_STORAGE}' in:"
|
||||
msg_custom " " "${YW}" "Datacenter → Storage → ${CONTAINER_STORAGE} → Edit → Content"
|
||||
msg_custom "📖" "${YW}" "See: https://pve.proxmox.com/wiki/Storage"
|
||||
msg_custom "🔗" "${YW}" "Help: https://github.com/community-scripts/ProxmoxVE/discussions"
|
||||
exit 213
|
||||
fi
|
||||
msg_ok "Storage '$CONTAINER_STORAGE' ($STORAGE_TYPE) validated"
|
||||
@@ -5789,9 +6229,23 @@ create_lxc_container() {
|
||||
msg_debug "Logfile: $LOGFILE"
|
||||
|
||||
# First attempt (PCT_OPTIONS is a multi-line string, use it directly)
|
||||
# Disable globbing: unquoted $PCT_OPTIONS needs word-splitting but must not glob-expand
|
||||
# (e.g. passwords containing * or ? would match filenames otherwise)
|
||||
set -f
|
||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" $PCT_OPTIONS >"$LOGFILE" 2>&1; then
|
||||
msg_debug "Container creation failed on ${TEMPLATE_STORAGE}. Checking error..."
|
||||
|
||||
# Check for Perl module breakage (partial PVE upgrade)
|
||||
if grep -qiE 'Compilation failed|Bareword.*not allowed' "$LOGFILE"; then
|
||||
msg_error "Container creation failed due to broken Perl modules on the PVE host."
|
||||
msg_custom "⚠️" "${YW}" "This usually happens after a partial PVE package upgrade."
|
||||
msg_custom "🔧" "${YW}" "Please run the following on the Proxmox host, then retry:"
|
||||
echo -e "${TAB} apt update && apt dist-upgrade -y"
|
||||
echo -e "${TAB} reboot"
|
||||
_flush_pct_log
|
||||
exit 232
|
||||
fi
|
||||
|
||||
# Check if CTID collision (race condition: ID claimed between validation and creation)
|
||||
if grep -qiE 'already exists|already in use' "$LOGFILE"; then
|
||||
local old_ctid="$CTID"
|
||||
@@ -5838,12 +6292,17 @@ create_lxc_container() {
|
||||
case $rc in
|
||||
0) : ;; # success - container created, continue
|
||||
2)
|
||||
msg_error "Upgrade declined. Please update and re-run: apt update && apt install --only-upgrade pve-container lxc-pve"
|
||||
msg_error "LXC stack upgrade ignored. Please inspect: $LOGFILE"
|
||||
_flush_pct_log
|
||||
exit 231
|
||||
;;
|
||||
3)
|
||||
msg_error "Upgrade and/or retry failed. Please inspect: $LOGFILE"
|
||||
msg_error "LXC stack upgrade failed. Please inspect: $LOGFILE"
|
||||
_flush_pct_log
|
||||
exit 231
|
||||
;;
|
||||
4)
|
||||
msg_error "Cancelled by user."
|
||||
_flush_pct_log
|
||||
exit 231
|
||||
;;
|
||||
@@ -5870,12 +6329,17 @@ create_lxc_container() {
|
||||
case $rc in
|
||||
0) : ;; # success - container created, continue
|
||||
2)
|
||||
msg_error "Upgrade declined. Please update and re-run: apt update && apt install --only-upgrade pve-container lxc-pve"
|
||||
msg_error "LXC stack upgrade ignored. Please inspect: $LOGFILE"
|
||||
_flush_pct_log
|
||||
exit 231
|
||||
;;
|
||||
3)
|
||||
msg_error "Upgrade and/or retry failed. Please inspect: $LOGFILE"
|
||||
msg_error "LXC stack upgrade failed. Please inspect: $LOGFILE"
|
||||
_flush_pct_log
|
||||
exit 231
|
||||
;;
|
||||
4)
|
||||
msg_error "Cancelled by user."
|
||||
_flush_pct_log
|
||||
exit 231
|
||||
;;
|
||||
@@ -5896,6 +6360,7 @@ create_lxc_container() {
|
||||
fi
|
||||
fi # close CTID collision else-branch
|
||||
fi
|
||||
set +f # re-enable globbing after pct create block
|
||||
|
||||
# Verify container exists (allow up to 10s for pmxcfs sync in clusters)
|
||||
local _pct_visible=false
|
||||
@@ -6001,6 +6466,40 @@ EOF
|
||||
systemctl start ping-instances.service
|
||||
fi
|
||||
|
||||
# Optional host-side post-install hook
|
||||
# Path comes from var_post_install (default.vars / app.vars / advanced settings).
|
||||
# Runs ON THE PROXMOX HOST after the container is up and configured.
|
||||
# Exposed env vars: APP, NSAPP, CTID, IP, HN, STORAGE, BRG.
|
||||
# Output (stdout/stderr) is captured to /var/log/community-scripts/post-install-<CTID>.log
|
||||
if [[ -n "${var_post_install:-}" ]]; then
|
||||
local _hook_log_dir="/var/log/community-scripts"
|
||||
local _hook_log="${_hook_log_dir}/post-install-${CTID}.log"
|
||||
mkdir -p "$_hook_log_dir" 2>/dev/null || true
|
||||
|
||||
if [[ ! -f "${var_post_install}" ]]; then
|
||||
msg_error "Post-install hook not found on host: ${var_post_install}"
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" \
|
||||
--title "POST-INSTALL HOOK FAILED" \
|
||||
--msgbox "The configured post-install hook was not found on the Proxmox host:\n\n${var_post_install}\n\nThe LXC was created successfully, but the hook did NOT run." 14 72 || true
|
||||
else
|
||||
msg_info "Running post-install hook: ${var_post_install}"
|
||||
local _hook_rc=0
|
||||
APP="$APP" NSAPP="${NSAPP:-}" CTID="$CTID" IP="$IP" HN="${HN:-}" \
|
||||
STORAGE="${STORAGE:-}" BRG="${BRG:-}" \
|
||||
bash "${var_post_install}" >"${_hook_log}" 2>&1 || _hook_rc=$?
|
||||
if [[ $_hook_rc -eq 0 ]]; then
|
||||
msg_ok "Post-install hook completed (log: ${_hook_log})"
|
||||
else
|
||||
msg_error "Post-install hook failed (rc=${_hook_rc}) – see ${_hook_log}"
|
||||
local _hook_tail=""
|
||||
_hook_tail="$(tail -n 15 "${_hook_log}" 2>/dev/null || true)"
|
||||
whiptail --backtitle "Proxmox VE Helper Scripts" \
|
||||
--title "POST-INSTALL HOOK FAILED" \
|
||||
--msgbox "Hook exited with code ${_hook_rc}.\n\nScript: ${var_post_install}\nLog: ${_hook_log}\n\n--- Last log lines ---\n${_hook_tail}\n\nThe LXC itself was created successfully." 22 78 || true
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
INSTALL_COMPLETE=true
|
||||
post_update_to_api "done" "none"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user