Update build.func
This commit is contained in:
parent
81329f74b1
commit
ca28e419ef
576
misc/build.func
576
misc/build.func
@ -2072,10 +2072,7 @@ build_container() {
|
||||
"
|
||||
export TEMPLATE_STORAGE="${var_template_storage:-}"
|
||||
export CONTAINER_STORAGE="${var_container_storage:-}"
|
||||
bash -c "$(curl -fsSL https://git.community-scripts.org/community-scripts/ProxmoxVED/raw/branch/main/misc/create_lxc.sh)" || exit
|
||||
if [ $? -ne 0 ]; then
|
||||
exit 200
|
||||
fi
|
||||
create_lxc_container || exit $?
|
||||
|
||||
LXC_CONFIG="/etc/pve/lxc/${CTID}.conf"
|
||||
|
||||
@ -2372,6 +2369,577 @@ destroy_lxc() {
|
||||
fi
|
||||
}
|
||||
|
||||
create_lxc_container() {
|
||||
# ------------------------------------------------------------------------------
|
||||
# Optional verbose mode (debug tracing)
|
||||
# ------------------------------------------------------------------------------
|
||||
if [[ "${CREATE_LXC_VERBOSE:-no}" == "yes" ]]; then set -x; fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Helpers (dynamic versioning / template parsing)
|
||||
# ------------------------------------------------------------------------------
|
||||
pkg_ver() { dpkg-query -W -f='${Version}\n' "$1" 2>/dev/null || echo ""; }
|
||||
pkg_cand() { apt-cache policy "$1" 2>/dev/null | awk '/Candidate:/ {print $2}'; }
|
||||
|
||||
ver_ge() { dpkg --compare-versions "$1" ge "$2"; }
|
||||
ver_gt() { dpkg --compare-versions "$1" gt "$2"; }
|
||||
ver_lt() { dpkg --compare-versions "$1" lt "$2"; }
|
||||
|
||||
# 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"; }
|
||||
|
||||
# Offer upgrade for pve-container/lxc-pve if candidate > installed; optional auto-retry pct create
|
||||
# Returns:
|
||||
# 0 = no upgrade needed
|
||||
# 1 = upgraded (and if do_retry=yes and retry succeeded, creation done)
|
||||
# 2 = user declined
|
||||
# 3 = upgrade attempted but failed OR retry failed
|
||||
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
|
||||
|
||||
_pvec_i="$(pkg_ver pve-container)"
|
||||
_lxcp_i="$(pkg_ver lxc-pve)"
|
||||
_pvec_c="$(pkg_cand pve-container)"
|
||||
_lxcp_c="$(pkg_cand lxc-pve)"
|
||||
|
||||
if [[ -n "$_pvec_c" && "$_pvec_c" != "none" ]]; then
|
||||
ver_gt "$_pvec_c" "${_pvec_i:-0}" && need=1
|
||||
fi
|
||||
if [[ -n "$_lxcp_c" && "$_lxcp_c" != "none" ]]; then
|
||||
ver_gt "$_lxcp_c" "${_lxcp_i:-0}" && need=1
|
||||
fi
|
||||
if [[ $need -eq 0 ]]; then
|
||||
msg_debug "No newer candidate for pve-container/lxc-pve (installed=$_pvec_i/$_lxcp_i, cand=$_pvec_c/$_lxcp_c)"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "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
|
||||
read -rp "Do you want to upgrade now? [y/N] " _ans
|
||||
case "${_ans,,}" in
|
||||
y | yes)
|
||||
msg_info "Upgrading Proxmox LXC stack (pve-container, lxc-pve)"
|
||||
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."
|
||||
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
|
||||
msg_ok "Container created successfully after upgrade."
|
||||
return 1
|
||||
else
|
||||
msg_error "pct create still failed after upgrade. See $LOGFILE"
|
||||
return 3
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
else
|
||||
msg_error "Upgrade failed. Please check APT output."
|
||||
return 3
|
||||
fi
|
||||
;;
|
||||
*) return 2 ;;
|
||||
esac
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Storage discovery / selection helpers
|
||||
# ------------------------------------------------------------------------------
|
||||
resolve_storage_preselect() {
|
||||
local class="$1" preselect="$2" required_content=""
|
||||
case "$class" in
|
||||
template) required_content="vztmpl" ;;
|
||||
container) required_content="rootdir" ;;
|
||||
*) return 1 ;;
|
||||
esac
|
||||
[[ -z "$preselect" ]] && return 1
|
||||
if ! pvesm status -content "$required_content" | awk 'NR>1{print $1}' | grep -qx -- "$preselect"; then
|
||||
msg_warn "Preselected storage '${preselect}' does not support content '${required_content}' (or not found)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local line total used free
|
||||
line="$(pvesm status | awk -v s="$preselect" 'NR>1 && $1==s {print $0}')"
|
||||
if [[ -z "$line" ]]; then
|
||||
STORAGE_INFO="n/a"
|
||||
else
|
||||
total="$(awk '{print $4}' <<<"$line")"
|
||||
used="$(awk '{print $5}' <<<"$line")"
|
||||
free="$(awk '{print $6}' <<<"$line")"
|
||||
local total_h used_h free_h
|
||||
if command -v numfmt >/dev/null 2>&1; then
|
||||
total_h="$(numfmt --to=iec --suffix=B --format %.1f "$total" 2>/dev/null || echo "$total")"
|
||||
used_h="$(numfmt --to=iec --suffix=B --format %.1f "$used" 2>/dev/null || echo "$used")"
|
||||
free_h="$(numfmt --to=iec --suffix=B --format %.1f "$free" 2>/dev/null || echo "$free")"
|
||||
STORAGE_INFO="Free: ${free_h} Used: ${used_h}"
|
||||
else
|
||||
STORAGE_INFO="Free: ${free} Used: ${used}"
|
||||
fi
|
||||
fi
|
||||
STORAGE_RESULT="$preselect"
|
||||
return 0
|
||||
}
|
||||
|
||||
check_storage_support() {
|
||||
local CONTENT="$1" VALID=0
|
||||
while IFS= read -r line; do
|
||||
local STORAGE_NAME
|
||||
STORAGE_NAME=$(awk '{print $1}' <<<"$line")
|
||||
[[ -n "$STORAGE_NAME" ]] && VALID=1
|
||||
done < <(pvesm status -content "$CONTENT" 2>/dev/null | awk 'NR>1')
|
||||
[[ $VALID -eq 1 ]]
|
||||
}
|
||||
|
||||
select_storage() {
|
||||
local CLASS=$1 CONTENT CONTENT_LABEL
|
||||
case $CLASS in
|
||||
container)
|
||||
CONTENT='rootdir'
|
||||
CONTENT_LABEL='Container'
|
||||
;;
|
||||
template)
|
||||
CONTENT='vztmpl'
|
||||
CONTENT_LABEL='Container template'
|
||||
;;
|
||||
iso)
|
||||
CONTENT='iso'
|
||||
CONTENT_LABEL='ISO image'
|
||||
;;
|
||||
images)
|
||||
CONTENT='images'
|
||||
CONTENT_LABEL='VM Disk image'
|
||||
;;
|
||||
backup)
|
||||
CONTENT='backup'
|
||||
CONTENT_LABEL='Backup'
|
||||
;;
|
||||
snippets)
|
||||
CONTENT='snippets'
|
||||
CONTENT_LABEL='Snippets'
|
||||
;;
|
||||
*)
|
||||
msg_error "Invalid storage class '$CLASS'"
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
|
||||
if [[ "$CONTENT" == "rootdir" && -n "${STORAGE:-}" ]]; then
|
||||
if pvesm status -content "$CONTENT" | awk 'NR>1 {print $1}' | grep -qx "$STORAGE"; then
|
||||
STORAGE_RESULT="$STORAGE"
|
||||
msg_info "Using preset storage: $STORAGE_RESULT for $CONTENT_LABEL"
|
||||
return 0
|
||||
else
|
||||
msg_error "Preset storage '$STORAGE' is not valid for content type '$CONTENT'."
|
||||
return 2
|
||||
fi
|
||||
fi
|
||||
|
||||
declare -A STORAGE_MAP
|
||||
local -a MENU=()
|
||||
local COL_WIDTH=0
|
||||
|
||||
while read -r TAG TYPE _ TOTAL USED FREE _; do
|
||||
[[ -n "$TAG" && -n "$TYPE" ]] || continue
|
||||
local DISPLAY="${TAG} (${TYPE})"
|
||||
local USED_FMT=$(numfmt --to=iec --from-unit=K --format %.1f <<<"$USED")
|
||||
local FREE_FMT=$(numfmt --to=iec --from-unit=K --format %.1f <<<"$FREE")
|
||||
local INFO="Free: ${FREE_FMT}B Used: ${USED_FMT}B"
|
||||
STORAGE_MAP["$DISPLAY"]="$TAG"
|
||||
MENU+=("$DISPLAY" "$INFO" "OFF")
|
||||
((${#DISPLAY} > COL_WIDTH)) && COL_WIDTH=${#DISPLAY}
|
||||
done < <(pvesm status -content "$CONTENT" | awk 'NR>1')
|
||||
|
||||
if [[ ${#MENU[@]} -eq 0 ]]; then
|
||||
msg_error "No storage found for content type '$CONTENT'."
|
||||
return 2
|
||||
fi
|
||||
|
||||
if [[ $((${#MENU[@]} / 3)) -eq 1 ]]; then
|
||||
STORAGE_RESULT="${STORAGE_MAP[${MENU[0]}]}"
|
||||
STORAGE_INFO="${MENU[1]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
local WIDTH=$((COL_WIDTH + 42))
|
||||
while true; do
|
||||
local DISPLAY_SELECTED
|
||||
DISPLAY_SELECTED=$(whiptail --backtitle "Proxmox VE Helper Scripts" \
|
||||
--title "Storage Pools" \
|
||||
--radiolist "Which storage pool for ${CONTENT_LABEL,,}?\n(Spacebar to select)" \
|
||||
16 "$WIDTH" 6 "${MENU[@]}" 3>&1 1>&2 2>&3) || exit_script
|
||||
|
||||
DISPLAY_SELECTED=$(sed 's/[[:space:]]*$//' <<<"$DISPLAY_SELECTED")
|
||||
if [[ -z "$DISPLAY_SELECTED" || -z "${STORAGE_MAP[$DISPLAY_SELECTED]+_}" ]]; then
|
||||
whiptail --msgbox "No valid storage selected. Please try again." 8 58
|
||||
continue
|
||||
fi
|
||||
STORAGE_RESULT="${STORAGE_MAP[$DISPLAY_SELECTED]}"
|
||||
for ((i = 0; i < ${#MENU[@]}; i += 3)); do
|
||||
if [[ "${MENU[$i]}" == "$DISPLAY_SELECTED" ]]; then
|
||||
STORAGE_INFO="${MENU[$i + 1]}"
|
||||
break
|
||||
fi
|
||||
done
|
||||
return 0
|
||||
done
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Required input variables
|
||||
# ------------------------------------------------------------------------------
|
||||
[[ "${CTID:-}" ]] || {
|
||||
msg_error "You need to set 'CTID' variable."
|
||||
exit 203
|
||||
}
|
||||
[[ "${PCT_OSTYPE:-}" ]] || {
|
||||
msg_error "You need to set 'PCT_OSTYPE' variable."
|
||||
exit 204
|
||||
}
|
||||
|
||||
msg_debug "CTID=$CTID"
|
||||
msg_debug "PCT_OSTYPE=$PCT_OSTYPE"
|
||||
msg_debug "PCT_OSVERSION=${PCT_OSVERSION:-default}"
|
||||
|
||||
# ID checks
|
||||
[[ "$CTID" -ge 100 ]] || {
|
||||
msg_error "ID cannot be less than 100."
|
||||
exit 205
|
||||
}
|
||||
if qm status "$CTID" &>/dev/null || pct status "$CTID" &>/dev/null; then
|
||||
echo -e "ID '$CTID' is already in use."
|
||||
unset CTID
|
||||
msg_error "Cannot use ID that is already in use."
|
||||
exit 206
|
||||
fi
|
||||
|
||||
# Storage capability check
|
||||
check_storage_support "rootdir" || {
|
||||
msg_error "No valid storage found for 'rootdir' [Container]"
|
||||
exit 1
|
||||
}
|
||||
check_storage_support "vztmpl" || {
|
||||
msg_error "No valid storage found for 'vztmpl' [Template]"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Template storage selection
|
||||
if resolve_storage_preselect template "${TEMPLATE_STORAGE:-}"; then
|
||||
TEMPLATE_STORAGE="$STORAGE_RESULT"
|
||||
TEMPLATE_STORAGE_INFO="$STORAGE_INFO"
|
||||
msg_ok "Storage ${BL}${TEMPLATE_STORAGE}${CL} (${TEMPLATE_STORAGE_INFO}) [Template]"
|
||||
else
|
||||
while true; do
|
||||
if select_storage template; then
|
||||
TEMPLATE_STORAGE="$STORAGE_RESULT"
|
||||
TEMPLATE_STORAGE_INFO="$STORAGE_INFO"
|
||||
msg_ok "Storage ${BL}${TEMPLATE_STORAGE}${CL} (${TEMPLATE_STORAGE_INFO}) [Template]"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Container storage selection
|
||||
if resolve_storage_preselect container "${CONTAINER_STORAGE:-}"; then
|
||||
CONTAINER_STORAGE="$STORAGE_RESULT"
|
||||
CONTAINER_STORAGE_INFO="$STORAGE_INFO"
|
||||
msg_ok "Storage ${BL}${CONTAINER_STORAGE}${CL} (${CONTAINER_STORAGE_INFO}) [Container]"
|
||||
else
|
||||
while true; do
|
||||
if select_storage container; then
|
||||
CONTAINER_STORAGE="$STORAGE_RESULT"
|
||||
CONTAINER_STORAGE_INFO="$STORAGE_INFO"
|
||||
msg_ok "Storage ${BL}${CONTAINER_STORAGE}${CL} (${CONTAINER_STORAGE_INFO}) [Container]"
|
||||
break
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Validate content types
|
||||
msg_info "Validating content types of storage '$CONTAINER_STORAGE'"
|
||||
STORAGE_CONTENT=$(grep -A4 -E "^(zfspool|dir|lvmthin|lvm): $CONTAINER_STORAGE" /etc/pve/storage.cfg | grep content | awk '{$1=""; print $0}' | xargs)
|
||||
msg_debug "Storage '$CONTAINER_STORAGE' has content types: $STORAGE_CONTENT"
|
||||
grep -qw "rootdir" <<<"$STORAGE_CONTENT" || {
|
||||
msg_error "Storage '$CONTAINER_STORAGE' does not support 'rootdir'. Cannot create LXC."
|
||||
exit 217
|
||||
}
|
||||
$STD msg_ok "Storage '$CONTAINER_STORAGE' supports 'rootdir'"
|
||||
|
||||
msg_info "Validating content types of template storage '$TEMPLATE_STORAGE'"
|
||||
TEMPLATE_CONTENT=$(grep -A4 -E "^[^:]+: $TEMPLATE_STORAGE" /etc/pve/storage.cfg | grep content | awk '{$1=""; print $0}' | xargs)
|
||||
msg_debug "Template storage '$TEMPLATE_STORAGE' has content types: $TEMPLATE_CONTENT"
|
||||
if ! grep -qw "vztmpl" <<<"$TEMPLATE_CONTENT"; then
|
||||
msg_warn "Template storage '$TEMPLATE_STORAGE' does not declare 'vztmpl'. This may cause pct create to fail."
|
||||
else
|
||||
$STD msg_ok "Template storage '$TEMPLATE_STORAGE' supports 'vztmpl'"
|
||||
fi
|
||||
|
||||
# Free space check
|
||||
STORAGE_FREE=$(pvesm status | awk -v s="$CONTAINER_STORAGE" '$1 == s { print $6 }')
|
||||
REQUIRED_KB=$((${PCT_DISK_SIZE:-8} * 1024 * 1024))
|
||||
[[ "$STORAGE_FREE" -ge "$REQUIRED_KB" ]] || {
|
||||
msg_error "Not enough space on '$CONTAINER_STORAGE'. Needed: ${PCT_DISK_SIZE:-8}G."
|
||||
exit 214
|
||||
}
|
||||
|
||||
# Cluster quorum (if cluster)
|
||||
if [[ -f /etc/pve/corosync.conf ]]; then
|
||||
msg_info "Checking cluster quorum"
|
||||
if ! pvecm status | awk -F':' '/^Quorate/ { exit ($2 ~ /Yes/) ? 0 : 1 }'; then
|
||||
msg_error "Cluster is not quorate. Start all nodes or configure quorum device (QDevice)."
|
||||
exit 210
|
||||
fi
|
||||
msg_ok "Cluster is quorate"
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Template discovery & validation
|
||||
# ------------------------------------------------------------------------------
|
||||
TEMPLATE_SEARCH="${PCT_OSTYPE}-${PCT_OSVERSION:-}"
|
||||
case "$PCT_OSTYPE" in
|
||||
debian | ubuntu) TEMPLATE_PATTERN="-standard_" ;;
|
||||
alpine | fedora | rocky | centos) TEMPLATE_PATTERN="-default_" ;;
|
||||
*) TEMPLATE_PATTERN="" ;;
|
||||
esac
|
||||
|
||||
msg_info "Searching for template '$TEMPLATE_SEARCH'"
|
||||
|
||||
mapfile -t LOCAL_TEMPLATES < <(
|
||||
pveam list "$TEMPLATE_STORAGE" 2>/dev/null |
|
||||
awk -v s="$TEMPLATE_SEARCH" -v p="$TEMPLATE_PATTERN" '$1 ~ s && $1 ~ p {print $1}' |
|
||||
sed 's|.*/||' | sort -t - -k 2 -V
|
||||
)
|
||||
|
||||
pveam update >/dev/null 2>&1 || msg_warn "Could not update template catalog (pveam update failed)."
|
||||
mapfile -t ONLINE_TEMPLATES < <(
|
||||
pveam available -section system 2>/dev/null |
|
||||
sed -n "s/.*\($TEMPLATE_SEARCH.*$TEMPLATE_PATTERN.*\)/\1/p" |
|
||||
sort -t - -k 2 -V
|
||||
)
|
||||
ONLINE_TEMPLATE=""
|
||||
[[ ${#ONLINE_TEMPLATES[@]} -gt 0 ]] && ONLINE_TEMPLATE="${ONLINE_TEMPLATES[-1]}"
|
||||
|
||||
if [[ ${#LOCAL_TEMPLATES[@]} -gt 0 ]]; then
|
||||
TEMPLATE="${LOCAL_TEMPLATES[-1]}"
|
||||
TEMPLATE_SOURCE="local"
|
||||
else
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
TEMPLATE_SOURCE="online"
|
||||
fi
|
||||
|
||||
TEMPLATE_PATH="$(pvesm path $TEMPLATE_STORAGE:vztmpl/$TEMPLATE 2>/dev/null || true)"
|
||||
if [[ -z "$TEMPLATE_PATH" ]]; then
|
||||
TEMPLATE_BASE=$(awk -v s="$TEMPLATE_STORAGE" '$1==s {f=1} f && /path/ {print $2; exit}' /etc/pve/storage.cfg)
|
||||
[[ -n "$TEMPLATE_BASE" ]] && TEMPLATE_PATH="$TEMPLATE_BASE/template/cache/$TEMPLATE"
|
||||
fi
|
||||
[[ -n "$TEMPLATE_PATH" ]] || {
|
||||
msg_error "Unable to resolve template path for $TEMPLATE_STORAGE. Check storage type and permissions."
|
||||
exit 220
|
||||
}
|
||||
|
||||
msg_ok "Template ${BL}$TEMPLATE${CL} [$TEMPLATE_SOURCE]"
|
||||
msg_debug "Resolved TEMPLATE_PATH=$TEMPLATE_PATH"
|
||||
|
||||
NEED_DOWNLOAD=0
|
||||
if [[ ! -f "$TEMPLATE_PATH" ]]; then
|
||||
msg_info "Template not present locally – will download."
|
||||
NEED_DOWNLOAD=1
|
||||
elif [[ ! -r "$TEMPLATE_PATH" ]]; then
|
||||
msg_error "Template file exists but is not readable – check permissions."
|
||||
exit 221
|
||||
elif [[ "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Template file too small (<1MB) – re-downloading."
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_warn "Template looks too small, but no online version exists. Keeping local file."
|
||||
fi
|
||||
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Template appears corrupted – re-downloading."
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_warn "Template appears corrupted, but no online version exists. Keeping local file."
|
||||
fi
|
||||
else
|
||||
$STD msg_ok "Template $TEMPLATE is present and valid."
|
||||
fi
|
||||
|
||||
if [[ "$TEMPLATE_SOURCE" == "local" && -n "$ONLINE_TEMPLATE" && "$TEMPLATE" != "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Local template is outdated: $TEMPLATE (latest available: $ONLINE_TEMPLATE)"
|
||||
if whiptail --yesno "A newer template is available:\n$ONLINE_TEMPLATE\n\nDo you want to download and use it instead?" 12 70; then
|
||||
TEMPLATE="$ONLINE_TEMPLATE"
|
||||
NEED_DOWNLOAD=1
|
||||
else
|
||||
msg_info "Continuing with local template $TEMPLATE"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$NEED_DOWNLOAD" -eq 1 ]]; then
|
||||
[[ -f "$TEMPLATE_PATH" ]] && rm -f "$TEMPLATE_PATH"
|
||||
for attempt in {1..3}; do
|
||||
msg_info "Attempt $attempt: Downloading template $TEMPLATE to $TEMPLATE_STORAGE"
|
||||
if pveam download "$TEMPLATE_STORAGE" "$TEMPLATE" >/dev/null 2>&1; then
|
||||
msg_ok "Template download successful."
|
||||
break
|
||||
fi
|
||||
if [[ $attempt -eq 3 ]]; then
|
||||
msg_error "Failed after 3 attempts. Please check network access, permissions, or manually run:\n pveam download $TEMPLATE_STORAGE $TEMPLATE"
|
||||
exit 222
|
||||
fi
|
||||
sleep $((attempt * 5))
|
||||
done
|
||||
fi
|
||||
|
||||
if ! pveam list "$TEMPLATE_STORAGE" 2>/dev/null | grep -q "$TEMPLATE"; then
|
||||
msg_error "Template $TEMPLATE not available in storage $TEMPLATE_STORAGE after download."
|
||||
exit 223
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Dynamic preflight for Debian 13.x: offer upgrade if available (no hard mins)
|
||||
# ------------------------------------------------------------------------------
|
||||
if [[ "$PCT_OSTYPE" == "debian" ]]; then
|
||||
OSVER="$(parse_template_osver "$TEMPLATE")"
|
||||
if [[ -n "$OSVER" ]]; then
|
||||
# Proactive, aber ohne Abbruch – nur Angebot
|
||||
offer_lxc_stack_upgrade_and_maybe_retry "no" || true
|
||||
fi
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Create LXC Container
|
||||
# ------------------------------------------------------------------------------
|
||||
msg_info "Creating LXC container"
|
||||
|
||||
# Ensure subuid/subgid entries exist
|
||||
grep -q "root:100000:65536" /etc/subuid || echo "root:100000:65536" >>/etc/subuid
|
||||
grep -q "root:100000:65536" /etc/subgid || echo "root:100000:65536" >>/etc/subgid
|
||||
|
||||
# Assemble pct options
|
||||
PCT_OPTIONS=(${PCT_OPTIONS[@]:-${DEFAULT_PCT_OPTIONS[@]}})
|
||||
[[ " ${PCT_OPTIONS[*]} " =~ " -rootfs " ]] || PCT_OPTIONS+=(-rootfs "$CONTAINER_STORAGE:${PCT_DISK_SIZE:-8}")
|
||||
|
||||
# Lock by template file (avoid concurrent downloads/creates)
|
||||
lockfile="/tmp/template.${TEMPLATE}.lock"
|
||||
exec 9>"$lockfile" || {
|
||||
msg_error "Failed to create lock file '$lockfile'."
|
||||
exit 200
|
||||
}
|
||||
flock -w 60 9 || {
|
||||
msg_error "Timeout while waiting for template lock."
|
||||
exit 211
|
||||
}
|
||||
|
||||
LOGFILE="/tmp/pct_create_${CTID}.log"
|
||||
msg_debug "pct create command: pct create $CTID ${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE} ${PCT_OPTIONS[*]}"
|
||||
msg_debug "Logfile: $LOGFILE"
|
||||
|
||||
# First attempt
|
||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >"$LOGFILE" 2>&1; then
|
||||
msg_error "Container creation failed on ${TEMPLATE_STORAGE}. Checking template..."
|
||||
|
||||
# Validate template file
|
||||
if [[ ! -s "$TEMPLATE_PATH" || "$(stat -c%s "$TEMPLATE_PATH")" -lt 1000000 ]]; then
|
||||
msg_warn "Template file too small or missing – re-downloading."
|
||||
rm -f "$TEMPLATE_PATH"
|
||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
|
||||
elif ! tar -tf "$TEMPLATE_PATH" &>/dev/null; then
|
||||
if [[ -n "$ONLINE_TEMPLATE" ]]; then
|
||||
msg_warn "Template appears corrupted – re-downloading."
|
||||
rm -f "$TEMPLATE_PATH"
|
||||
pveam download "$TEMPLATE_STORAGE" "$TEMPLATE"
|
||||
else
|
||||
msg_warn "Template appears corrupted, but no online version exists. Skipping re-download."
|
||||
fi
|
||||
fi
|
||||
|
||||
# Retry after repair
|
||||
if ! pct create "$CTID" "${TEMPLATE_STORAGE}:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
|
||||
# Fallback to local storage
|
||||
if [[ "$TEMPLATE_STORAGE" != "local" ]]; then
|
||||
msg_warn "Retrying container creation with fallback to local storage..."
|
||||
LOCAL_TEMPLATE_PATH="/var/lib/vz/template/cache/$TEMPLATE"
|
||||
if [[ ! -f "$LOCAL_TEMPLATE_PATH" ]]; then
|
||||
msg_info "Downloading template to local..."
|
||||
pveam download local "$TEMPLATE" >/dev/null 2>&1
|
||||
fi
|
||||
if pct create "$CTID" "local:vztmpl/${TEMPLATE}" "${PCT_OPTIONS[@]}" >>"$LOGFILE" 2>&1; then
|
||||
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."
|
||||
if offer_lxc_stack_upgrade_and_maybe_retry "yes"; then
|
||||
: # success after retry
|
||||
else
|
||||
rc=$?
|
||||
case $rc in
|
||||
2) echo "Upgrade was declined. Please update and re-run:
|
||||
apt update && apt install --only-upgrade pve-container lxc-pve" ;;
|
||||
3) echo "Upgrade and/or retry failed. Please inspect: $LOGFILE" ;;
|
||||
esac
|
||||
exit 231
|
||||
fi
|
||||
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
|
||||
else
|
||||
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
|
||||
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."
|
||||
if offer_lxc_stack_upgrade_and_maybe_retry "yes"; then
|
||||
: # success after retry
|
||||
else
|
||||
rc=$?
|
||||
case $rc in
|
||||
2) echo "Upgrade was declined. Please update and re-run:
|
||||
apt update && apt install --only-upgrade pve-container lxc-pve" ;;
|
||||
3) echo "Upgrade and/or retry failed. Please inspect: $LOGFILE" ;;
|
||||
esac
|
||||
exit 231
|
||||
fi
|
||||
else
|
||||
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
|
||||
fi
|
||||
|
||||
# Verify container exists
|
||||
pct list | awk '{print $1}' | grep -qx "$CTID" || {
|
||||
msg_error "Container ID $CTID not listed in 'pct list'. See $LOGFILE"
|
||||
exit 215
|
||||
}
|
||||
|
||||
# Verify config rootfs
|
||||
grep -q '^rootfs:' "/etc/pve/lxc/$CTID.conf" || {
|
||||
msg_error "RootFS entry missing in container config. See $LOGFILE"
|
||||
exit 216
|
||||
}
|
||||
|
||||
msg_ok "LXC Container ${BL}$CTID${CL} ${GN}was successfully created."
|
||||
}
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# description()
|
||||
#
|
||||
|
Loading…
x
Reference in New Issue
Block a user