diff --git a/vm/debian-13-vm.sh b/vm/debian-13-vm.sh index 7be0c8cce..a15acd842 100644 --- a/vm/debian-13-vm.sh +++ b/vm/debian-13-vm.sh @@ -65,13 +65,62 @@ trap 'error_handler $LINENO "$BASH_COMMAND"' ERR trap cleanup EXIT trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM + +# Smart recovery state +VM_CREATION_PHASE="no" +VM_RECOVERY_ATTEMPT=0 +VM_MAX_RETRIES=2 + function error_handler() { local exit_code="$?" local line_number="$1" local command="$2" local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" - post_update_to_api "failed" "${exit_code}" echo -e "\n$error_message\n" + + # During VM creation phase: offer recovery menu instead of immediate cleanup + if [[ "$VM_CREATION_PHASE" == "yes" && $VM_RECOVERY_ATTEMPT -lt $VM_MAX_RETRIES ]]; then + ((VM_RECOVERY_ATTEMPT++)) + trap - ERR + set +e + + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "VM CREATION FAILED" \ + --radiolist "Exit code: ${exit_code} | Attempt: ${VM_RECOVERY_ATTEMPT}/${VM_MAX_RETRIES}\nFailed command: ${command}\n\nChoose a recovery action:" 16 72 4 \ + "RETRY" "Retry VM creation" "ON" \ + "SKIP_CUSTOMIZE" "Retry and skip image customization" "OFF" \ + "KEEP" "Keep partial VM for debugging" "OFF" \ + "ABORT" "Destroy VM and exit" "OFF" \ + 3>&1 1>&2 2>&3) || choice="ABORT" + + case "$choice" in + RETRY | SKIP_CUSTOMIZE) + msg_info "Cleaning up failed VM ${VMID} for retry" + cleanup_vmid 2>/dev/null || true + [[ "$choice" == "SKIP_CUSTOMIZE" ]] && export SKIP_VIRT_CUSTOMIZE="yes" + msg_ok "Ready for retry (attempt $((VM_RECOVERY_ATTEMPT + 1))/${VM_MAX_RETRIES})" + set -e + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR + create_vm + exit $? + ;; + KEEP) + echo -e "\n${YW} Keeping partial VM ${VMID} for debugging${CL}" + echo -e " Inspect: qm config ${VMID}" + echo -e " Remove: qm destroy ${VMID} --destroy-unreferenced-disks --purge\n" + post_update_to_api "failed" "$exit_code" + exit "$exit_code" + ;; + *) + post_update_to_api "failed" "$exit_code" + cleanup_vmid + exit "$exit_code" + ;; + esac + fi + + # Default: no recovery (max retries exceeded or outside creation phase) + post_update_to_api "failed" "${exit_code}" cleanup_vmid } @@ -485,6 +534,7 @@ fi msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." +create_vm() { # ============================================================================== # PREREQUISITES # ============================================================================== @@ -511,11 +561,12 @@ msg_ok "Downloaded ${CL}${BL}${FILE}${CL}" # ============================================================================== # IMAGE CUSTOMIZATION # ============================================================================== -msg_info "Customizing ${FILE} image" - WORK_FILE=$(mktemp --suffix=.qcow2) cp "$FILE" "$WORK_FILE" +if [[ "${SKIP_VIRT_CUSTOMIZE:-}" != "yes" ]]; then +msg_info "Customizing ${FILE} image" + # Set hostname virt-customize -q -a "$WORK_FILE" --hostname "${HN}" >/dev/null 2>&1 @@ -551,6 +602,9 @@ EOF' >/dev/null 2>&1 || true fi msg_ok "Customized image" +else + msg_ok "Skipped image customization (will configure on first boot)" +fi STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}') case $STORAGE_TYPE in @@ -650,3 +704,8 @@ fi msg_ok "Completed successfully!\n" echo "More Info at https://github.com/community-scripts/ProxmoxVE/discussions/836" +} # end create_vm + +VM_CREATION_PHASE="yes" +create_vm +VM_CREATION_PHASE="no" diff --git a/vm/haos-vm.sh b/vm/haos-vm.sh index f4d2239c2..8d6ade88c 100644 --- a/vm/haos-vm.sh +++ b/vm/haos-vm.sh @@ -69,13 +69,65 @@ trap 'error_handler $LINENO "$BASH_COMMAND"' ERR trap cleanup EXIT trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM + +# Smart recovery state +VM_CREATION_PHASE="no" +VM_RECOVERY_ATTEMPT=0 +VM_MAX_RETRIES=2 + function error_handler() { local exit_code="$?" local line_number="$1" local command="$2" local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" - post_update_to_api "failed" "${exit_code}" echo -e "\n$error_message\n" + + # During VM creation phase: offer recovery menu instead of immediate cleanup + if [[ "$VM_CREATION_PHASE" == "yes" && $VM_RECOVERY_ATTEMPT -lt $VM_MAX_RETRIES ]]; then + ((VM_RECOVERY_ATTEMPT++)) + trap - ERR + set +e + + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "VM CREATION FAILED" \ + --radiolist "Exit code: ${exit_code} | Attempt: ${VM_RECOVERY_ATTEMPT}/${VM_MAX_RETRIES}\nFailed command: ${command}\n\nChoose a recovery action:" 16 72 4 \ + "RETRY" "Retry VM creation" "ON" \ + "RETRY_DOWNLOAD" "Retry with fresh download (clear cache)" "OFF" \ + "KEEP" "Keep partial VM for debugging" "OFF" \ + "ABORT" "Destroy VM and exit" "OFF" \ + 3>&1 1>&2 2>&3) || choice="ABORT" + + case "$choice" in + RETRY | RETRY_DOWNLOAD) + msg_info "Cleaning up failed VM ${VMID} for retry" + cleanup_vmid 2>/dev/null || true + if [[ "$choice" == "RETRY_DOWNLOAD" && -n "${CACHE_FILE:-}" ]]; then + rm -f "$CACHE_FILE" + msg_ok "Cleared cached image" + fi + msg_ok "Ready for retry (attempt $((VM_RECOVERY_ATTEMPT + 1))/${VM_MAX_RETRIES})" + set -e + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR + create_vm + exit $? + ;; + KEEP) + echo -e "\n${YW} Keeping partial VM ${VMID} for debugging${CL}" + echo -e " Inspect: qm config ${VMID}" + echo -e " Remove: qm destroy ${VMID} --destroy-unreferenced-disks --purge\n" + post_update_to_api "failed" "$exit_code" + exit "$exit_code" + ;; + *) + post_update_to_api "failed" "$exit_code" + cleanup_vmid + exit "$exit_code" + ;; + esac + fi + + # Default: no recovery (max retries exceeded or outside creation phase) + post_update_to_api "failed" "${exit_code}" cleanup_vmid } @@ -554,6 +606,7 @@ fi msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." +create_vm() { var_version="${BRANCH}" msg_info "Retrieving the URL for Home Assistant ${BRANCH} Disk Image" if [ "$BRANCH" == "$dev" ]; then @@ -658,3 +711,8 @@ if [ "$START_VM" == "yes" ]; then fi post_update_to_api "done" "none" msg_ok "Completed successfully!\n" +} # end create_vm + +VM_CREATION_PHASE="yes" +create_vm +VM_CREATION_PHASE="no" diff --git a/vm/openwrt-vm.sh b/vm/openwrt-vm.sh index b68dd5845..96442cc11 100644 --- a/vm/openwrt-vm.sh +++ b/vm/openwrt-vm.sh @@ -70,13 +70,61 @@ trap 'error_handler $LINENO "$BASH_COMMAND"' ERR trap cleanup EXIT trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM + +# Smart recovery state +VM_CREATION_PHASE="no" +VM_RECOVERY_ATTEMPT=0 +VM_MAX_RETRIES=2 + function error_handler() { local exit_code="$?" local line_number="$1" local command="$2" - post_update_to_api "failed" "$exit_code" local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" echo -e "\n$error_message\n" + + # During VM creation phase: offer recovery menu instead of immediate cleanup + if [[ "$VM_CREATION_PHASE" == "yes" && $VM_RECOVERY_ATTEMPT -lt $VM_MAX_RETRIES ]]; then + ((VM_RECOVERY_ATTEMPT++)) + trap - ERR + set +e + set +o pipefail + + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "VM CREATION FAILED" \ + --radiolist "Exit code: ${exit_code} | Attempt: ${VM_RECOVERY_ATTEMPT}/${VM_MAX_RETRIES}\nFailed command: ${command}\n\nChoose a recovery action:" 16 72 3 \ + "RETRY" "Retry VM creation" "ON" \ + "KEEP" "Keep partial VM for debugging" "OFF" \ + "ABORT" "Destroy VM and exit" "OFF" \ + 3>&1 1>&2 2>&3) || choice="ABORT" + + case "$choice" in + RETRY) + msg_info "Cleaning up failed VM ${VMID} for retry" + cleanup_vmid 2>/dev/null || true + msg_ok "Ready for retry (attempt $((VM_RECOVERY_ATTEMPT + 1))/${VM_MAX_RETRIES})" + set -Eeo pipefail + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR + create_vm + exit $? + ;; + KEEP) + echo -e "\n${YW} Keeping partial VM ${VMID} for debugging${CL}" + echo -e " Inspect: qm config ${VMID}" + echo -e " Remove: qm destroy ${VMID} --destroy-unreferenced-disks --purge\n" + post_update_to_api "failed" "$exit_code" + exit "$exit_code" + ;; + *) + post_update_to_api "failed" "$exit_code" + cleanup_vmid + exit "$exit_code" + ;; + esac + fi + + # Default: no recovery (max retries exceeded or outside creation phase) + post_update_to_api "failed" "$exit_code" cleanup_vmid } @@ -520,6 +568,8 @@ else fi msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." + +create_vm() { msg_info "Getting URL for OpenWrt Disk Image" response=$(curl -fsSL https://openwrt.org) @@ -661,3 +711,8 @@ if [ -z "$VLAN" ] && [ "$VLAN2" != "999" ]; then fi post_update_to_api "done" "none" msg_ok "Completed Successfully!${VLAN_FINISH:+\n$VLAN_FINISH}" +} # end create_vm + +VM_CREATION_PHASE="yes" +create_vm +VM_CREATION_PHASE="no" diff --git a/vm/ubuntu2204-vm.sh b/vm/ubuntu2204-vm.sh index dd9b2872a..5ca95512a 100644 --- a/vm/ubuntu2204-vm.sh +++ b/vm/ubuntu2204-vm.sh @@ -62,13 +62,60 @@ trap 'error_handler $LINENO "$BASH_COMMAND"' ERR trap cleanup EXIT trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM + +# Smart recovery state +VM_CREATION_PHASE="no" +VM_RECOVERY_ATTEMPT=0 +VM_MAX_RETRIES=2 + function error_handler() { local exit_code="$?" local line_number="$1" local command="$2" - post_update_to_api "failed" "$exit_code" local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" echo -e "\n$error_message\n" + + # During VM creation phase: offer recovery menu instead of immediate cleanup + if [[ "$VM_CREATION_PHASE" == "yes" && $VM_RECOVERY_ATTEMPT -lt $VM_MAX_RETRIES ]]; then + ((VM_RECOVERY_ATTEMPT++)) + trap - ERR + set +e + + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "VM CREATION FAILED" \ + --radiolist "Exit code: ${exit_code} | Attempt: ${VM_RECOVERY_ATTEMPT}/${VM_MAX_RETRIES}\nFailed command: ${command}\n\nChoose a recovery action:" 16 72 3 \ + "RETRY" "Retry VM creation" "ON" \ + "KEEP" "Keep partial VM for debugging" "OFF" \ + "ABORT" "Destroy VM and exit" "OFF" \ + 3>&1 1>&2 2>&3) || choice="ABORT" + + case "$choice" in + RETRY) + msg_info "Cleaning up failed VM ${VMID} for retry" + cleanup_vmid 2>/dev/null || true + msg_ok "Ready for retry (attempt $((VM_RECOVERY_ATTEMPT + 1))/${VM_MAX_RETRIES})" + set -e + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR + create_vm + exit $? + ;; + KEEP) + echo -e "\n${YW} Keeping partial VM ${VMID} for debugging${CL}" + echo -e " Inspect: qm config ${VMID}" + echo -e " Remove: qm destroy ${VMID} --destroy-unreferenced-disks --purge\n" + post_update_to_api "failed" "$exit_code" + exit "$exit_code" + ;; + *) + post_update_to_api "failed" "$exit_code" + cleanup_vmid + exit "$exit_code" + ;; + esac + fi + + # Default: no recovery (max retries exceeded or outside creation phase) + post_update_to_api "failed" "$exit_code" cleanup_vmid } @@ -466,6 +513,8 @@ else fi msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." + +create_vm() { msg_info "Retrieving the URL for the Ubuntu 22.04 Disk Image" URL=https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img sleep 2 @@ -562,3 +611,8 @@ post_update_to_api "done" "none" msg_ok "Completed successfully!\n" echo -e "Setup Cloud-Init before starting \n More info at https://github.com/community-scripts/ProxmoxVE/discussions/272 \n" +} # end create_vm + +VM_CREATION_PHASE="yes" +create_vm +VM_CREATION_PHASE="no" diff --git a/vm/ubuntu2404-vm.sh b/vm/ubuntu2404-vm.sh index 67f7a3bd2..b98177d3f 100644 --- a/vm/ubuntu2404-vm.sh +++ b/vm/ubuntu2404-vm.sh @@ -65,13 +65,60 @@ trap 'error_handler $LINENO "$BASH_COMMAND"' ERR trap cleanup EXIT trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM + +# Smart recovery state +VM_CREATION_PHASE="no" +VM_RECOVERY_ATTEMPT=0 +VM_MAX_RETRIES=2 + function error_handler() { local exit_code="$?" local line_number="$1" local command="$2" - post_update_to_api "failed" "$exit_code" local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" echo -e "\n$error_message\n" + + # During VM creation phase: offer recovery menu instead of immediate cleanup + if [[ "$VM_CREATION_PHASE" == "yes" && $VM_RECOVERY_ATTEMPT -lt $VM_MAX_RETRIES ]]; then + ((VM_RECOVERY_ATTEMPT++)) + trap - ERR + set +e + + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "VM CREATION FAILED" \ + --radiolist "Exit code: ${exit_code} | Attempt: ${VM_RECOVERY_ATTEMPT}/${VM_MAX_RETRIES}\nFailed command: ${command}\n\nChoose a recovery action:" 16 72 3 \ + "RETRY" "Retry VM creation" "ON" \ + "KEEP" "Keep partial VM for debugging" "OFF" \ + "ABORT" "Destroy VM and exit" "OFF" \ + 3>&1 1>&2 2>&3) || choice="ABORT" + + case "$choice" in + RETRY) + msg_info "Cleaning up failed VM ${VMID} for retry" + cleanup_vmid 2>/dev/null || true + msg_ok "Ready for retry (attempt $((VM_RECOVERY_ATTEMPT + 1))/${VM_MAX_RETRIES})" + set -e + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR + create_vm + exit $? + ;; + KEEP) + echo -e "\n${YW} Keeping partial VM ${VMID} for debugging${CL}" + echo -e " Inspect: qm config ${VMID}" + echo -e " Remove: qm destroy ${VMID} --destroy-unreferenced-disks --purge\n" + post_update_to_api "failed" "$exit_code" + exit "$exit_code" + ;; + *) + post_update_to_api "failed" "$exit_code" + cleanup_vmid + exit "$exit_code" + ;; + esac + fi + + # Default: no recovery (max retries exceeded or outside creation phase) + post_update_to_api "failed" "$exit_code" cleanup_vmid } @@ -468,6 +515,8 @@ else fi msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." + +create_vm() { msg_info "Retrieving the URL for the Ubuntu 24.04 Disk Image" URL=https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img sleep 2 @@ -564,3 +613,8 @@ post_update_to_api "done" "none" msg_ok "Completed successfully!\n" echo -e "Setup Cloud-Init before starting \n More info at https://github.com/community-scripts/ProxmoxVE/discussions/272 \n" +} # end create_vm + +VM_CREATION_PHASE="yes" +create_vm +VM_CREATION_PHASE="no" diff --git a/vm/ubuntu2504-vm.sh b/vm/ubuntu2504-vm.sh index a285f7218..95b048145 100644 --- a/vm/ubuntu2504-vm.sh +++ b/vm/ubuntu2504-vm.sh @@ -64,13 +64,60 @@ trap 'error_handler $LINENO "$BASH_COMMAND"' ERR trap cleanup EXIT trap 'post_update_to_api "failed" "INTERRUPTED"' SIGINT trap 'post_update_to_api "failed" "TERMINATED"' SIGTERM + +# Smart recovery state +VM_CREATION_PHASE="no" +VM_RECOVERY_ATTEMPT=0 +VM_MAX_RETRIES=2 + function error_handler() { local exit_code="$?" local line_number="$1" local command="$2" - post_update_to_api "failed" "$exit_code" local error_message="${RD}[ERROR]${CL} in line ${RD}$line_number${CL}: exit code ${RD}$exit_code${CL}: while executing command ${YW}$command${CL}" echo -e "\n$error_message\n" + + # During VM creation phase: offer recovery menu instead of immediate cleanup + if [[ "$VM_CREATION_PHASE" == "yes" && $VM_RECOVERY_ATTEMPT -lt $VM_MAX_RETRIES ]]; then + ((VM_RECOVERY_ATTEMPT++)) + trap - ERR + set +e + + local choice + choice=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "VM CREATION FAILED" \ + --radiolist "Exit code: ${exit_code} | Attempt: ${VM_RECOVERY_ATTEMPT}/${VM_MAX_RETRIES}\nFailed command: ${command}\n\nChoose a recovery action:" 16 72 3 \ + "RETRY" "Retry VM creation" "ON" \ + "KEEP" "Keep partial VM for debugging" "OFF" \ + "ABORT" "Destroy VM and exit" "OFF" \ + 3>&1 1>&2 2>&3) || choice="ABORT" + + case "$choice" in + RETRY) + msg_info "Cleaning up failed VM ${VMID} for retry" + cleanup_vmid 2>/dev/null || true + msg_ok "Ready for retry (attempt $((VM_RECOVERY_ATTEMPT + 1))/${VM_MAX_RETRIES})" + set -e + trap 'error_handler $LINENO "$BASH_COMMAND"' ERR + create_vm + exit $? + ;; + KEEP) + echo -e "\n${YW} Keeping partial VM ${VMID} for debugging${CL}" + echo -e " Inspect: qm config ${VMID}" + echo -e " Remove: qm destroy ${VMID} --destroy-unreferenced-disks --purge\n" + post_update_to_api "failed" "$exit_code" + exit "$exit_code" + ;; + *) + post_update_to_api "failed" "$exit_code" + cleanup_vmid + exit "$exit_code" + ;; + esac + fi + + # Default: no recovery (max retries exceeded or outside creation phase) + post_update_to_api "failed" "$exit_code" cleanup_vmid } @@ -467,6 +514,8 @@ else fi msg_ok "Using ${CL}${BL}$STORAGE${CL} ${GN}for Storage Location." msg_ok "Virtual Machine ID is ${CL}${BL}$VMID${CL}." + +create_vm() { msg_info "Retrieving the URL for the Ubuntu 25.04 Disk Image" URL=https://cloud-images.ubuntu.com/plucky/current/plucky-server-cloudimg-amd64.img sleep 2 @@ -563,3 +612,8 @@ post_update_to_api "done" "none" msg_ok "Completed successfully!\n" echo -e "Setup Cloud-Init before starting \n More info at https://github.com/community-scripts/ProxmoxVE/discussions/272 \n" +} # end create_vm + +VM_CREATION_PHASE="yes" +create_vm +VM_CREATION_PHASE="no"