2025-05-01 23:35:19 +02:00
#!/usr/bin/env bash
# ==========================================================
2025-05-07 23:50:20 +02:00
# ProxMenuX - Virtual Machine Creator Script
2025-05-01 23:35:19 +02:00
# ==========================================================
2025-05-07 23:50:20 +02:00
# Author : MacRimi
# Copyright : (c) 2024 MacRimi
2026-01-19 17:15:00 +01:00
# License : (GPL-3.0) (https://github.com/MacRimi/ProxMenux/blob/main/LICENSE)
2025-05-07 23:50:20 +02:00
# Version : 1.0
# Last Updated: 07/05/2025
# ==========================================================
# Description:
# This script is part of the central ProxMenux VM creation module. It allows users
# to create virtual machines (VMs) in Proxmox VE using either default or advanced
# configurations, streamlining the deployment of Linux, Windows, and other systems.
#
# Key features:
# - Supports both virtual disk creation and physical disk passthrough.
# - Automates CPU, RAM, BIOS, network and storage configuration.
# - Provides a user-friendly menu to select OS type, ISO image and disk interface.
# - Automatically generates a detailed and styled HTML description for each VM.
#
# All operations are designed to simplify and accelerate VM creation in a
# consistent and maintainable way, using ProxMenux standards.
2025-05-01 23:35:19 +02:00
# ==========================================================
2026-04-05 11:24:08 +02:00
SCRIPT_DIR = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) " && pwd ) "
LOCAL_SCRIPTS_LOCAL = " $( cd " $SCRIPT_DIR /.." && pwd ) "
LOCAL_SCRIPTS_DEFAULT = "/usr/local/share/proxmenux/scripts"
LOCAL_SCRIPTS = " $LOCAL_SCRIPTS_DEFAULT "
2025-05-01 23:35:19 +02:00
BASE_DIR = "/usr/local/share/proxmenux"
2026-04-05 11:24:08 +02:00
UTILS_FILE = " $LOCAL_SCRIPTS /utils.sh"
if [[ -f " $LOCAL_SCRIPTS_LOCAL /utils.sh" ]] ; then
LOCAL_SCRIPTS = " $LOCAL_SCRIPTS_LOCAL "
UTILS_FILE = " $LOCAL_SCRIPTS /utils.sh"
elif [[ ! -f " $UTILS_FILE " ]] ; then
UTILS_FILE = " $BASE_DIR /utils.sh"
fi
2025-05-01 23:35:19 +02:00
VENV_PATH = "/opt/googletrans-env"
if [[ -f " $UTILS_FILE " ]] ; then
source " $UTILS_FILE "
fi
2026-04-05 11:24:08 +02:00
if [[ -f " $LOCAL_SCRIPTS_LOCAL /global/vm_storage_helpers.sh" ]] ; then
source " $LOCAL_SCRIPTS_LOCAL /global/vm_storage_helpers.sh"
elif [[ -f " $LOCAL_SCRIPTS_DEFAULT /global/vm_storage_helpers.sh" ]] ; then
source " $LOCAL_SCRIPTS_DEFAULT /global/vm_storage_helpers.sh"
fi
2026-05-14 14:45:45 +02:00
if [[ -f " $LOCAL_SCRIPTS_LOCAL /global/iso_storage_helpers.sh" ]] ; then
source " $LOCAL_SCRIPTS_LOCAL /global/iso_storage_helpers.sh"
elif [[ -f " $LOCAL_SCRIPTS_DEFAULT /global/iso_storage_helpers.sh" ]] ; then
source " $LOCAL_SCRIPTS_DEFAULT /global/iso_storage_helpers.sh"
fi
2026-04-05 11:24:08 +02:00
if [[ -f " $LOCAL_SCRIPTS_LOCAL /global/pci_passthrough_helpers.sh" ]] ; then
source " $LOCAL_SCRIPTS_LOCAL /global/pci_passthrough_helpers.sh"
elif [[ -f " $LOCAL_SCRIPTS_DEFAULT /global/pci_passthrough_helpers.sh" ]] ; then
source " $LOCAL_SCRIPTS_DEFAULT /global/pci_passthrough_helpers.sh"
fi
2025-05-01 23:35:19 +02:00
load_language
initialize_cache
2026-04-06 17:16:26 +02:00
VM_STORAGE_IOMMU_PENDING_REBOOT = " ${ VM_STORAGE_IOMMU_PENDING_REBOOT :- 0 } "
2025-05-01 23:35:19 +02:00
# ==========================================================
2025-05-07 23:11:50 +02:00
# Mont ISOs
2025-05-01 23:35:19 +02:00
# ==========================================================
function mount_iso_to_vm() {
local vmid = " $1 "
local iso_path = " $2 "
local device = " $3 "
2026-05-14 14:45:45 +02:00
local iso_volid = " ${ 4 :- } "
local iso_label
2025-05-01 23:35:19 +02:00
2026-05-14 14:45:45 +02:00
if [[ -z " $iso_volid " && -n " $iso_path " ]] ; then
if [[ " $iso_path " == *":iso/" * ]] ; then
iso_volid = " $iso_path "
elif [[ -f " $iso_path " ]] && declare -F iso_path_to_volid >/dev/null 2>& 1; then
iso_volid = $( iso_path_to_volid " $iso_path " 2>/dev/null || true )
fi
fi
if [[ -z " $iso_volid " ]] ; then
2025-05-01 23:35:19 +02:00
msg_warn " $( translate "ISO not found to mount on device" ) $device "
2026-05-14 14:45:45 +02:00
return 1
fi
iso_label = " $( basename " ${ iso_volid #*: } " ) "
if qm set " $vmid " -$device " ${ iso_volid } ,media=cdrom" >/dev/null 2>& 1; then
msg_ok " $( translate "Mounted ISO on device" ) $device → $iso_label "
else
msg_warn " $( translate "Could not mount ISO on device" ) $device → $iso_volid "
return 1
2025-05-01 23:35:19 +02:00
fi
}
# ==========================================================
# Select Interface Type
# ==========================================================
function select_interface_type() {
INTERFACE_TYPE = $( whiptail --backtitle "ProxMenux" --title " $( translate "Select Disk Interface" ) " --radiolist \
" $( translate "Select the bus type for the disks:" ) " 15 70 4 \
"scsi" " $( translate "SCSI (recommended for Linux and Windows)" ) " ON \
"sata" " $( translate "SATA (standard - high compatibility)" ) " OFF \
"virtio" " $( translate "VirtIO (advanced - high performance)" ) " OFF \
"ide" "IDE (legacy)" OFF \
2026-04-05 11:24:08 +02:00
3>& 1 1>& 2 2>& 3) || {
msg_warn " $( translate "Disk interface selection cancelled." ) " >& 2
return 1
}
2025-05-01 23:35:19 +02:00
case " $INTERFACE_TYPE " in
"scsi" | "sata" )
DISCARD_OPTS = ",discard=on,ssd=on"
;;
"virtio" )
DISCARD_OPTS = ",discard=on"
;;
"ide" )
DISCARD_OPTS = ""
;;
esac
msg_ok " $( translate "Disk interface selected:" ) $INTERFACE_TYPE "
}
2026-04-06 13:39:07 +02:00
function prompt_controller_conflict_policy() {
local pci = " $1 "
shift
local -a source_vms =( " $@ " )
local msg vmid vm_name st ob
2026-04-12 20:32:34 +02:00
msg = "\n $( translate "Selected controller/NVMe is already assigned to other VM(s):" ) \n\n"
2026-04-06 13:39:07 +02:00
for vmid in " ${ source_vms [@] } " ; do
vm_name = $( _vm_name_by_id " $vmid " )
st = "stopped" ; _vm_status_is_running " $vmid " && st = "running"
ob = "0" ; _vm_onboot_is_enabled " $vmid " && ob = "1"
msg += " - VM ${ vmid } ( ${ vm_name } ) [ ${ st } , onboot= ${ ob } ]\n"
done
msg += "\n $( translate "Choose action for this controller/NVMe:" ) "
local choice
2026-04-12 20:32:34 +02:00
choice = $( whiptail --title " $( translate "Controller/NVMe Conflict Policy" ) " --menu " $msg " 20 80 10 \
2026-04-06 13:39:07 +02:00
"1" " $( translate "Keep in source VM(s) + disable onboot + add to target VM" ) " \
"2" " $( translate "Move to target VM (remove from source VM config)" ) " \
"3" " $( translate "Skip this device" ) " \
3>& 1 1>& 2 2>& 3) || { echo "skip" ; return ; }
case " $choice " in
1) echo "keep_disable_onboot" ;;
2) echo "move_remove_source" ;;
*) echo "skip" ;;
esac
}
2025-05-01 23:35:19 +02:00
# ==========================================================
2025-05-07 23:11:50 +02:00
# EFI/TPM
2025-05-01 23:35:19 +02:00
# ==========================================================
2025-05-02 18:31:09 +02:00
function select_storage_target() {
local PURPOSE = " $1 "
local vmid = " $2 "
2025-05-01 23:35:19 +02:00
local STORAGE = ""
2025-05-02 18:31:09 +02:00
local STORAGE_MENU =()
2025-05-01 23:35:19 +02:00
while read -r line; do
TAG = $( echo " $line " | awk '{print $1}' )
TYPE = $( echo " $line " | awk '{printf "%-10s", $2}' )
FREE = $( echo " $line " | numfmt --field 4-6 --from-unit= K --to= iec --format "%.2f" | awk '{printf("%9sB", $6)}' )
2025-05-02 18:31:09 +02:00
STORAGE_MENU +=( " $TAG " " $( translate "Type:" ) $TYPE $( translate "Free:" ) $FREE " "OFF" )
2025-05-01 23:35:19 +02:00
done < <( pvesm status -content images | awk 'NR>1' )
2025-05-02 18:31:09 +02:00
if [[ ${# STORAGE_MENU [@] } -eq 0 ]] ; then
2026-04-05 11:24:08 +02:00
msg_error " $( translate "Unable to detect a valid storage location for $PURPOSE disk." ) " >& 2
return 1
2025-05-02 18:31:09 +02:00
elif [[ $(( ${# STORAGE_MENU [@] } / 3 )) -eq 1 ]] ; then
STORAGE = " ${ STORAGE_MENU [0] } "
2025-05-01 23:35:19 +02:00
else
2026-04-05 11:24:08 +02:00
[[ -n " ${ SPINNER_PID :- } " ]] && kill " $SPINNER_PID " >/dev/null 2>& 1
2026-09-22 19:00:03 +02:00
local storage_prompt
case " $PURPOSE " in
EFI) storage_prompt = $( translate "Choose the storage for the EFI disk (4MB):" ) ;;
TPM) storage_prompt = $( translate "Choose the storage for the TPM disk (4MB):" ) ;;
*) storage_prompt = $( translate "Choose the storage volume for the $PURPOSE disk (4MB):" ) ;;
esac
2025-05-02 18:31:09 +02:00
STORAGE = $( whiptail --backtitle "ProxMenux" --title " $( translate " $PURPOSE Disk Storage" ) " --radiolist \
2026-09-22 19:00:03 +02:00
" $storage_prompt " $'\n\n' " $( translate "Use Spacebar to select." ) " 16 70 6 \
2026-04-05 11:24:08 +02:00
" ${ STORAGE_MENU [@] } " 3>& 1 1>& 2 2>& 3) || {
msg_warn " $( translate " $PURPOSE disk storage selection cancelled." ) " >& 2
return 1
}
2025-05-01 23:35:19 +02:00
fi
2026-04-05 11:24:08 +02:00
[[ -z " $STORAGE " ]] && return 1
2025-05-01 23:35:19 +02:00
echo " $STORAGE "
}
2025-05-02 15:41:27 +02:00
# ==========================================================
# Guest Agent Configurator
# ==========================================================
function configure_guest_agent() {
if [[ -z " $VMID " ]] ; then
msg_error " $( translate "No VMID defined. Cannot apply guest agent config." ) "
return 1
fi
msg_info " $( translate "Adding QEMU Guest Agent support..." ) "
2026-09-25 21:51:12 +02:00
# Enable the agent on the VM
2025-05-02 15:41:27 +02:00
qm set " $VMID " -agent enabled = 1 >/dev/null 2>& 1
# Añadir canal de comunicación virtio
qm set " $VMID " -chardev socket,id= qga0,path= /var/run/qemu-server/$VMID .qga,server= on,wait= off >/dev/null 2>& 1
qm set " $VMID " -device virtio-serial-pci -device virtserialport,chardev= qga0,name= org.qemu.guest_agent.0 >/dev/null 2>& 1
msg_ok " $( translate "Guest Agent configuration applied" ) "
}
2026-04-05 11:24:08 +02:00
function run_gpu_passthrough_wizard() {
[[ " ${ WIZARD_ADD_GPU :- no } " != "yes" ]] && return 0
local gpu_script = " $LOCAL_SCRIPTS /gpu_tpu/add_gpu_vm.sh"
local wizard_result_file = ""
if [[ ! -f " $gpu_script " ]] ; then
local local_gpu_script
local_gpu_script = " $( cd " $( dirname " ${ BASH_SOURCE [0] } " ) " /.. && pwd ) /gpu_tpu/add_gpu_vm.sh"
[[ -f " $local_gpu_script " ]] && gpu_script = " $local_gpu_script "
fi
if [[ ! -f " $gpu_script " ]] ; then
2026-09-24 22:27:26 +02:00
local gpu_notice
gpu_notice = " $( translate "GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again." ) "
[[ " $gpu_notice " == *'{menu}' * && " $gpu_notice " == *'{action}' * ]] || gpu_notice = "GPU passthrough assistant not found. Later, open {menu} → {action} from the main menu to try again."
2026-09-26 18:23:07 +02:00
gpu_notice = " ${ gpu_notice // \{ menu \} / " $( translate "Hardware: GPUs and Coral-TPU" ) " } "
gpu_notice = " ${ gpu_notice // \{ action \} / " $( translate "Add GPU to VM (Intel | AMD | NVIDIA)" ) " } "
2026-09-24 22:27:26 +02:00
msg_warn " $gpu_notice "
2026-04-05 11:24:08 +02:00
return 0
fi
msg_info2 " $( translate "Launching GPU passthrough assistant for VM" ) ${ VMID } ..."
wizard_result_file = "/tmp/proxmenux_gpu_wizard_result_ ${ VMID } _ $$ .txt"
: >" $wizard_result_file "
bash " $gpu_script " --vmid " $VMID " --wizard --result-file " $wizard_result_file "
if [[ -s " $wizard_result_file " ]] ; then
WIZARD_GPU_RESULT = $( head -n1 " $wizard_result_file " | tr -d '\r\n' )
else
WIZARD_GPU_RESULT = "cancelled"
fi
rm -f " $wizard_result_file "
}
2025-05-02 15:41:27 +02:00
2025-05-02 18:31:09 +02:00
2025-05-01 23:35:19 +02:00
# ==========================================================
2025-05-07 23:11:50 +02:00
# Create VM
2025-05-01 23:35:19 +02:00
# ==========================================================
function create_vm() {
local BOOT_ORDER = ""
local DISK_INFO = ""
local DISK_INDEX = 0
local ISO_DIR = "/var/lib/vz/template/iso"
if [[ -n " $ISO_PATH " && -n " $ISO_URL " && ! -f " $ISO_PATH " ]] ; then
2025-05-07 23:11:50 +02:00
2025-05-01 23:35:19 +02:00
if [[ " $ISO_URL " == *"sourceforge.net" * ]] ; then
2025-05-07 23:11:50 +02:00
2025-05-01 23:35:19 +02:00
wget --content-disposition --show-progress -O " $ISO_PATH " " $ISO_URL "
else
2025-05-07 23:11:50 +02:00
2025-05-01 23:35:19 +02:00
wget --no-verbose --show-progress -O " $ISO_PATH " " $ISO_URL "
fi
2025-05-07 23:11:50 +02:00
2025-05-01 23:35:19 +02:00
if [[ -f " $ISO_PATH " ]] ; then
2026-05-14 14:45:45 +02:00
ISO_VOLID = " ${ ISO_VOLID :- local : iso / $( basename " $ISO_PATH " ) } "
2025-05-01 23:35:19 +02:00
msg_ok " $( translate "ISO image downloaded" ) "
else
msg_error " $( translate "Failed to download ISO image" ) "
2026-04-05 11:24:08 +02:00
return 1
2025-05-01 23:35:19 +02:00
fi
fi
2025-05-06 13:34:29 +02:00
if [[ " $OS_TYPE " == "2" ]] ; then
GUEST_OS_TYPE = "win10"
else
GUEST_OS_TYPE = "l26"
fi
2025-05-01 23:35:19 +02:00
2026-04-05 11:24:08 +02:00
local VM_TAGS = "proxmenux"
case " ${ OS_TYPE :- } " in
1) VM_TAGS = "proxmenux,nas" ;;
2) VM_TAGS = "proxmenux,windows" ;;
*) VM_TAGS = "proxmenux,linux" ;;
esac
2025-05-01 23:35:19 +02:00
2025-05-07 23:11:50 +02:00
2025-10-20 19:20:50 +02:00
# qm create "$VMID" -agent 1${MACHINE} -tablet 0 -localtime 1${BIOS_TYPE}${CPU_TYPE} \
# -cores "$CORE_COUNT" -memory "$RAM_SIZE" -name "$HN" -tags proxmenux \
# -net0 "virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU" -ostype "$GUEST_OS_TYPE" \
# -scsihw virtio-scsi-pci \
# $( [[ -n "$SERIAL_PORT" ]] && echo "-serial0 $SERIAL_PORT" ) >/dev/null 2>&1
2026-04-06 17:16:26 +02:00
if ! qm create " $VMID " \
2025-10-20 19:20:50 +02:00
-agent 1${ MACHINE :+ $MACHINE } \
-localtime 1${ BIOS_TYPE :+ $BIOS_TYPE }${ CPU_TYPE :+ $CPU_TYPE } \
-cores " $CORE_COUNT " \
-memory " $RAM_SIZE " \
-name " $HN " \
2026-04-05 11:24:08 +02:00
-tags " $VM_TAGS " \
2025-10-20 19:20:50 +02:00
-net0 "virtio,bridge= $BRG ,macaddr= $MAC$VLAN$MTU " \
-ostype " $GUEST_OS_TYPE " \
-scsihw virtio-scsi-pci \
$( [[ -n " $SERIAL_PORT " ]] && echo "-serial0 $SERIAL_PORT " ) \
2026-04-06 17:16:26 +02:00
>/dev/null 2>& 1; then
msg_error " $( translate "Failed to create base VM. Check VM ID and host configuration." ) "
return 1
fi
2025-10-20 19:20:50 +02:00
if [[ " $OS_TYPE " == "2" ]] ; then
qm set " $VMID " -tablet 1 >/dev/null 2>& 1
fi
2025-05-01 23:35:19 +02:00
msg_ok " $( translate "Base VM created with ID" ) $VMID "
2025-05-07 23:11:50 +02:00
2025-05-09 19:06:36 +02:00
if [[ " $BIOS_TYPE " == *"ovmf" * ]] ; then
msg_info " $( translate "Configuring EFI disk" ) "
2026-04-05 11:24:08 +02:00
if ! EFI_STORAGE = $( select_storage_target "EFI" " $VMID " ) ; then
msg_error " $( translate "EFI storage selection failed or was cancelled. VM creation aborted." ) "
return 1
fi
2025-05-09 19:06:36 +02:00
STORAGE_TYPE = $( pvesm status -storage " $EFI_STORAGE " | awk 'NR>1 {print $2}' )
EFI_DISK_ID = "efidisk0"
EFI_KEYS = "0"
[[ " $OS_TYPE " == "2" ]] && EFI_KEYS = "1"
if [[ " $STORAGE_TYPE " == "btrfs" || " $STORAGE_TYPE " == "dir" || " $STORAGE_TYPE " == "nfs" ]] ; then
if qm set " $VMID " -$EFI_DISK_ID " $EFI_STORAGE :4,efitype=4m,format=raw,pre-enrolled-keys= $EFI_KEYS " >/dev/null 2>& 1; then
msg_ok " $( translate "EFI disk created and configured on" ) $EFI_STORAGE "
else
msg_error " $( translate "Failed to configure EFI disk" ) "
fi
else
2025-05-01 23:35:19 +02:00
EFI_DISK_NAME = "vm- ${ VMID } -disk-efivars"
2025-05-09 19:06:36 +02:00
if pvesm alloc " $EFI_STORAGE " " $VMID " " $EFI_DISK_NAME " 4M >/dev/null 2>& 1; then
if qm set " $VMID " -$EFI_DISK_ID " $EFI_STORAGE : $EFI_DISK_NAME ,pre-enrolled-keys= $EFI_KEYS " >/dev/null 2>& 1; then
2025-05-01 23:35:19 +02:00
msg_ok " $( translate "EFI disk created and configured on" ) $EFI_STORAGE "
else
msg_error " $( translate "Failed to configure EFI disk" ) "
fi
else
msg_error " $( translate "Failed to create EFI disk" ) "
fi
fi
2025-05-09 19:06:36 +02:00
fi
2025-05-01 23:35:19 +02:00
2025-05-02 14:25:11 +02:00
2025-05-07 23:11:50 +02:00
2025-05-09 19:06:36 +02:00
if [[ " $OS_TYPE " == "2" ]] ; then
msg_info " $( translate "Configuring TPM device" ) "
2026-04-05 11:24:08 +02:00
if ! TPM_STORAGE = $( select_storage_target "TPM" " $VMID " ) ; then
msg_error " $( translate "TPM storage selection failed or was cancelled. VM creation aborted." ) "
return 1
fi
2025-05-09 19:06:36 +02:00
STORAGE_TYPE = $( pvesm status -storage " $TPM_STORAGE " | awk 'NR>1 {print $2}' )
TPM_ID = "tpmstate0"
if [[ " $STORAGE_TYPE " == "btrfs" || " $STORAGE_TYPE " == "dir" || " $STORAGE_TYPE " == "nfs" ]] ; then
if qm set " $VMID " -$TPM_ID " $TPM_STORAGE :4,version=v2.0,format=raw" >/dev/null 2>& 1; then
msg_ok " $( translate "TPM device added to VM" ) "
else
msg_error " $( translate "Failed to configure TPM device in VM" ) "
fi
else
2025-05-02 14:25:11 +02:00
TPM_NAME = "vm- ${ VMID } -tpmstate"
2025-05-09 19:06:36 +02:00
if pvesm alloc " $TPM_STORAGE " " $VMID " " $TPM_NAME " 4M >/dev/null 2>& 1; then
if qm set " $VMID " -$TPM_ID " $TPM_STORAGE : $TPM_NAME ,size=4M,version=v2.0" >/dev/null 2>& 1; then
2025-05-02 18:31:09 +02:00
msg_ok " $( translate "TPM device added to VM" ) "
else
2025-05-09 19:06:36 +02:00
msg_error " $( translate "Failed to configure TPM device in VM" ) "
2025-05-02 18:31:09 +02:00
fi
2025-05-02 14:25:11 +02:00
else
2025-05-02 18:31:09 +02:00
msg_error " $( translate "Failed to create TPM state disk" ) "
2025-05-02 14:25:11 +02:00
fi
fi
2025-05-09 19:06:36 +02:00
fi
2025-05-02 14:25:11 +02:00
2025-05-02 18:31:09 +02:00
2025-05-01 23:35:19 +02:00
# ==========================================================
2026-04-05 11:24:08 +02:00
# Create Disks / Import Disks / Controller + NVMe
2025-05-01 23:35:19 +02:00
# ==========================================================
2026-04-05 11:24:08 +02:00
local -a EFFECTIVE_IMPORT_DISKS =()
if [[ ${# IMPORT_DISKS [@] } -gt 0 ]] ; then
EFFECTIVE_IMPORT_DISKS =( " ${ IMPORT_DISKS [@] } " )
elif [[ ${# PASSTHROUGH_DISKS [@] } -gt 0 ]] ; then
EFFECTIVE_IMPORT_DISKS =( " ${ PASSTHROUGH_DISKS [@] } " )
fi
2025-05-07 23:11:50 +02:00
2026-04-05 11:24:08 +02:00
if [[ ${# VIRTUAL_DISKS [@] } -gt 0 || ${# EFFECTIVE_IMPORT_DISKS [@] } -gt 0 ]] ; then
if ! select_interface_type; then
msg_error " $( translate "Disk interface is required to continue VM creation." ) "
return 1
fi
fi
2025-05-01 23:35:19 +02:00
2026-04-05 11:24:08 +02:00
local NEXT_DISK_SLOT = 0
if [[ ${# VIRTUAL_DISKS [@] } -gt 0 ]] ; then
2025-05-09 19:26:06 +02:00
for i in " ${ !VIRTUAL_DISKS[@] } " ; do
2026-04-05 11:24:08 +02:00
DISK_INDEX = $(( NEXT_DISK_SLOT+1))
2025-05-09 19:26:06 +02:00
IFS = ':' read -r STORAGE SIZE <<< " ${ VIRTUAL_DISKS [ $i ] } "
DISK_NAME = "vm- ${ VMID } -disk- ${ DISK_INDEX } "
2026-04-05 11:24:08 +02:00
SLOT_NAME = " ${ INTERFACE_TYPE }${ NEXT_DISK_SLOT } "
2025-05-09 19:06:36 +02:00
2025-05-09 19:26:06 +02:00
STORAGE_TYPE = $( pvesm status -storage " $STORAGE " | awk 'NR>1 {print $2}' )
case " $STORAGE_TYPE " in
dir| nfs| btrfs)
DISK_EXT = ".raw"
DISK_REF = " $VMID /"
;;
*)
DISK_EXT = ""
DISK_REF = ""
;;
esac
if [[ " $STORAGE_TYPE " == "btrfs" || " $STORAGE_TYPE " == "dir" || " $STORAGE_TYPE " == "nfs" ]] ; then
if qm set " $VMID " -$SLOT_NAME " $STORAGE : ${ SIZE } ,format=raw ${ DISCARD_OPTS } " >/dev/null 2>& 1; then
2025-05-09 19:06:36 +02:00
msg_ok " $( translate "Virtual disk" ) $DISK_INDEX ${ SIZE } GB - $STORAGE ( $SLOT_NAME )"
DISK_INFO += "<p>Virtual Disk $DISK_INDEX : ${ SIZE } GB ( $STORAGE / $SLOT_NAME )</p>"
[[ -z " $BOOT_ORDER " ]] && BOOT_ORDER = " $SLOT_NAME "
2026-04-05 11:24:08 +02:00
NEXT_DISK_SLOT = $(( NEXT_DISK_SLOT + 1 ))
2025-05-09 19:06:36 +02:00
else
msg_error " $( translate "Failed to assign virtual disk" ) $DISK_INDEX "
fi
else
2025-05-09 19:26:06 +02:00
#DISK_NAME="vm-${VMID}-disk-${DISK_INDEX}"
if pvesm alloc " $STORAGE " " $VMID " " $DISK_NAME$DISK_EXT " " $SIZE " G >/dev/null 2>& 1; then
qm set " $VMID " -$SLOT_NAME " $STORAGE : ${ DISK_REF }${ DISK_NAME }${ DISK_EXT }${ DISCARD_OPTS } " >/dev/null
msg_ok " $( translate "Virtual disk" ) $DISK_INDEX ${ SIZE } GB - $STORAGE ( $SLOT_NAME )"
DISK_INFO += "<p>Virtual Disk $DISK_INDEX : ${ SIZE } GB ( $STORAGE / $SLOT_NAME )</p>"
[[ -z " $BOOT_ORDER " ]] && BOOT_ORDER = " $SLOT_NAME "
2026-04-05 11:24:08 +02:00
NEXT_DISK_SLOT = $(( NEXT_DISK_SLOT + 1 ))
2025-05-09 19:26:06 +02:00
else
msg_error " $( translate "Failed to create disk" ) $DISK_INDEX "
fi
2025-05-09 19:06:36 +02:00
fi
2025-05-09 19:26:06 +02:00
done
fi
2025-05-01 23:35:19 +02:00
2026-04-05 11:24:08 +02:00
if [[ ${# EFFECTIVE_IMPORT_DISKS [@] } -gt 0 ]] ; then
for i in " ${ !EFFECTIVE_IMPORT_DISKS[@] } " ; do
SLOT_NAME = " ${ INTERFACE_TYPE }${ NEXT_DISK_SLOT } "
DISK = " ${ EFFECTIVE_IMPORT_DISKS [ $i ] } "
2025-05-01 23:35:19 +02:00
MODEL = $( lsblk -ndo MODEL " $DISK " )
SIZE = $( lsblk -ndo SIZE " $DISK " )
qm set " $VMID " -$SLOT_NAME " $DISK ${ DISCARD_OPTS } " >/dev/null 2>& 1
2026-04-05 11:24:08 +02:00
msg_ok " $( translate "Import disk assigned" ) ( $DISK → $SLOT_NAME )"
DISK_INFO += "<p>Import Disk $(( NEXT_DISK_SLOT+1)) : $DISK ( $MODEL $SIZE )</p>"
2025-05-01 23:35:19 +02:00
[[ -z " $BOOT_ORDER " ]] && BOOT_ORDER = " $SLOT_NAME "
2026-04-05 11:24:08 +02:00
NEXT_DISK_SLOT = $(( NEXT_DISK_SLOT + 1 ))
2025-05-01 23:35:19 +02:00
done
fi
2026-04-19 12:26:52 +02:00
if [[ ${# CONTROLLER_NVME_PCIS [@] } -gt 0 ]] ; then
# SR-IOV guard: drop Virtual Functions / active-PFs before staging.
# Proxmox's VFIO rebind via qm hostpci would trigger the same VF-tree
# collapse described in the GPU flows, so we exclude them and tell
# the user to manage those passthroughs manually.
#
# UI choice: this runs mid-flow (phase 2 of the wizard, interleaved
# with msg_info/msg_ok output), so a whiptail msgbox is used to force
# the user to acknowledge the exclusion instead of letting the notice
# scroll by with the rest of the processing output. After the user
# clicks OK, a per-device msg_warn is emitted so the skipped BDFs
# remain visible in the captured log.
if declare -F _pci_sriov_filter_array >/dev/null 2>& 1; then
local _sriov_removed = ""
_sriov_removed = $( _pci_sriov_filter_array CONTROLLER_NVME_PCIS)
if [[ -n " $_sriov_removed " ]] ; then
local _sriov_msg = "" _entry _bdf _role _first _sb
local -a _sriov_bdfs =()
local _nl = $'\n'
_sriov_msg = " $( translate "The following devices were excluded from Controller/NVMe passthrough because they are part of an SR-IOV configuration:" ) "
while IFS = read -r _entry; do
[[ -z " $_entry " ]] && continue
_bdf = " ${ _entry %%|* } "
_role = " ${ _entry #*| } "
_first = " ${ _role %% * } "
_sriov_bdfs +=( " $_bdf " )
if [[ " $_first " == "vf" ]] ; then
_sriov_msg += " ${ _nl } • ${ _bdf } — $( translate "Virtual Function" ) "
else
_sriov_msg += " ${ _nl } • ${ _bdf } — $( translate "Physical Function with" ) ${ _role #pf-active } $( translate "active VFs" ) "
fi
done <<< " $_sriov_removed "
_sriov_msg += " ${ _nl }${ _nl } $( translate "To pass SR-IOV Virtual Functions to a VM, edit the VM configuration manually via the Proxmox web interface." ) "
whiptail --backtitle "ProxMenux" \
--title " $( translate "SR-IOV Configuration Detected" ) " \
--msgbox " $_sriov_msg " 18 82
for _sb in " ${ _sriov_bdfs [@] } " ; do
msg_warn " $( translate "Skipping SR-IOV device" ) : ${ _sb } "
done
fi
fi
if [[ ${# CONTROLLER_NVME_PCIS [@] } -eq 0 ]] ; then
msg_warn " $( translate "No eligible Controller/NVMe devices remain after SR-IOV filtering. Skipping." ) "
fi
fi
2026-04-05 11:24:08 +02:00
if [[ ${# CONTROLLER_NVME_PCIS [@] } -gt 0 ]] ; then
2026-04-06 19:13:31 +02:00
local CONTROLLER_CAN_STAGE = true
2026-04-06 17:16:26 +02:00
if declare -F _pci_is_iommu_active >/dev/null 2>& 1 && ! _pci_is_iommu_active; then
if [[ " ${ VM_STORAGE_IOMMU_PENDING_REBOOT :- 0 } " == "1" ]] ; then
msg_warn " $( translate "IOMMU was configured during this wizard and a reboot is pending." ) "
2026-04-06 19:13:31 +02:00
msg_warn " $( translate "Controller + NVMe assignment will be written now and become active after host reboot." ) "
2026-04-06 17:16:26 +02:00
else
msg_error " $( translate "IOMMU is not active. Skipping Controller + NVMe assignment." ) "
2026-04-06 19:13:31 +02:00
CONTROLLER_CAN_STAGE = false
2026-04-06 17:16:26 +02:00
fi
2026-04-06 19:13:31 +02:00
fi
if [[ " $CONTROLLER_CAN_STAGE " != "true" ]] ; then
:
2026-04-06 17:16:26 +02:00
elif ! _vm_is_q35 " $VMID " ; then
2026-04-05 11:24:08 +02:00
msg_error " $( translate "Controller + NVMe passthrough requires machine type q35. Skipping controller assignment." ) "
else
local hostpci_idx = 0
if declare -F _pci_next_hostpci_index >/dev/null 2>& 1; then
hostpci_idx = $( _pci_next_hostpci_index " $VMID " 2>/dev/null || echo 0)
else
local hostpci_existing
hostpci_existing = $( qm config " $VMID " 2>/dev/null)
while grep -q "^hostpci ${ hostpci_idx } :" <<< " $hostpci_existing " ; do
hostpci_idx = $(( hostpci_idx + 1 ))
done
fi
local pci bdf
for pci in " ${ CONTROLLER_NVME_PCIS [@] } " ; do
bdf = " ${ pci #0000: } "
if declare -F _pci_function_assigned_to_vm >/dev/null 2>& 1; then
if _pci_function_assigned_to_vm " $pci " " $VMID " ; then
msg_warn " $( translate "Controller/NVMe already present in VM config" ) ( $pci )"
continue
fi
elif qm config " $VMID " 2>/dev/null | grep -qE "^hostpci[0-9]+:.*(0000:)? ${ bdf } ([,[:space:]]| $)" ; then
msg_warn " $( translate "Controller/NVMe already present in VM config" ) ( $pci )"
continue
fi
2026-04-06 13:39:07 +02:00
local -a source_vms =()
mapfile -t source_vms < <( _pci_assigned_vm_ids " $pci " " $VMID " 2>/dev/null)
if [[ ${# source_vms [@] } -gt 0 ]] ; then
local has_running = false vmid action slot_base
for vmid in " ${ source_vms [@] } " ; do
if _vm_status_is_running " $vmid " ; then
has_running = true
msg_warn " $( translate "Controller/NVMe is in use by running VM" ) ${ vmid } ( $( translate "stop source VM first" ) )"
fi
done
if $has_running ; then
continue
fi
action = $( prompt_controller_conflict_policy " $pci " " ${ source_vms [@] } " )
case " $action " in
keep_disable_onboot)
for vmid in " ${ source_vms [@] } " ; do
if _vm_onboot_is_enabled " $vmid " ; then
if qm set " $vmid " -onboot 0 >/dev/null 2>& 1; then
msg_warn " $( translate "Start on boot disabled for VM" ) ${ vmid } "
fi
fi
done
;;
move_remove_source)
slot_base = $( _pci_slot_base " $pci " )
for vmid in " ${ source_vms [@] } " ; do
if _remove_pci_slot_from_vm_config " $vmid " " $slot_base " ; then
msg_ok " $( translate "Controller/NVMe removed from source VM" ) ${ vmid } ( ${ pci } )"
fi
done
;;
*)
msg_info2 " $( translate "Skipped device" ) : ${ pci } "
continue
;;
esac
fi
2026-04-05 11:24:08 +02:00
if qm set " $VMID " --hostpci${ hostpci_idx } " ${ pci } ,pcie=1" >/dev/null 2>& 1; then
msg_ok " $( translate "Controller/NVMe assigned" ) (hostpci ${ hostpci_idx } → ${ pci } )"
DISK_INFO += "<p>Controller/NVMe: ${ pci } </p>"
2026-04-12 20:32:34 +02:00
BOOT_ORDER = " ${ BOOT_ORDER :+ $BOOT_ORDER ; } hostpci ${ hostpci_idx } "
2026-04-05 11:24:08 +02:00
hostpci_idx = $(( hostpci_idx + 1 ))
else
msg_error " $( translate "Failed to assign Controller/NVMe" ) ( ${ pci } )"
fi
done
2026-04-06 13:39:07 +02:00
2026-04-05 11:24:08 +02:00
fi
fi
2025-05-01 23:35:19 +02:00
2025-05-07 23:11:50 +02:00
2026-05-14 14:45:45 +02:00
if [[ -n " ${ ISO_VOLID :- } " || -f " ${ ISO_PATH :- } " ]] ; then
mount_iso_to_vm " $VMID " " $ISO_PATH " "ide2" " ${ ISO_VOLID :- } "
2025-05-01 23:35:19 +02:00
fi
2025-05-07 23:11:50 +02:00
2025-05-02 16:30:00 +02:00
if [[ " $OS_TYPE " == "2" ]] ; then
2025-05-01 23:35:19 +02:00
local VIRTIO_DIR = "/var/lib/vz/template/iso"
local VIRTIO_SELECTED = ""
2026-05-14 14:45:45 +02:00
local VIRTIO_VOLID = ""
2025-05-01 23:35:19 +02:00
local VIRTIO_DOWNLOAD_URL = "https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso"
while true; do
VIRTIO_OPTION = $( whiptail --title "ProxMenux - VirtIO Drivers" --menu " $( translate "Select how to provide VirtIO drivers" ) " 15 70 2 \
"1" " $( translate "Download latest VirtIO ISO automatically" ) " \
"2" " $( translate "Use existing VirtIO ISO from storage" ) " 3>& 1 1>& 2 2>& 3)
[[ $? -ne 0 ]] && msg_warn " $( translate "VirtIO ISO selection cancelled." ) " && break
case " $VIRTIO_OPTION " in
1)
if [[ -f " $VIRTIO_DIR /virtio-win.iso" ]] ; then
if whiptail --title "ProxMenux" --yesno " $( translate "A VirtIO ISO already exists. Do you want to overwrite it?" ) " 10 60; then
wget -q --show-progress -O " $VIRTIO_DIR /virtio-win.iso" " $VIRTIO_DOWNLOAD_URL "
if [[ -f " $VIRTIO_DIR /virtio-win.iso" ]] ; then
msg_ok " $( translate "VirtIO driver ISO downloaded successfully." ) "
else
msg_error " $( translate "Failed to download VirtIO driver ISO." ) "
fi
fi
else
wget -q --show-progress -O " $VIRTIO_DIR /virtio-win.iso" " $VIRTIO_DOWNLOAD_URL "
if [[ -f " $VIRTIO_DIR /virtio-win.iso" ]] ; then
msg_ok " $( translate "VirtIO driver ISO downloaded successfully." ) "
else
msg_error " $( translate "Failed to download VirtIO driver ISO." ) "
fi
fi
VIRTIO_SELECTED = " $VIRTIO_DIR /virtio-win.iso"
2026-05-14 14:45:45 +02:00
VIRTIO_VOLID = "local:iso/virtio-win.iso"
2025-05-01 23:35:19 +02:00
;;
2)
2026-05-14 14:45:45 +02:00
local virtio_volid
2025-05-01 23:35:19 +02:00
VIRTIO_LIST =()
2026-05-14 14:45:45 +02:00
while read -r virtio_volid; do
[[ -z " $virtio_volid " ]] && continue
VIRTIO_LIST +=( " $virtio_volid " " $( iso_dialog_description " $virtio_volid " ) " )
done < <( iso_list_volids "virtio" )
2025-05-01 23:35:19 +02:00
if [[ ${# VIRTIO_LIST [@] } -eq 0 ]] ; then
msg_warn " $( translate "No VirtIO ISO found. Please download one." ) "
2025-05-07 23:11:50 +02:00
continue
2025-05-01 23:35:19 +02:00
fi
2026-05-14 14:45:45 +02:00
VIRTIO_VOLID = $( whiptail --title "ProxMenux - VirtIO ISOs" --menu " $( translate "Select a VirtIO ISO to use:" ) \n\n $( printf '%-42s │ %-14s │ %s' " $( translate "ISO" ) " " $( translate "Storage" ) " " $( translate "Size" ) " ) " 22 86 12 " ${ VIRTIO_LIST [@] } " 3>& 1 1>& 2 2>& 3)
2025-05-01 23:35:19 +02:00
2026-05-14 14:45:45 +02:00
if [[ -n " $VIRTIO_VOLID " ]] ; then
VIRTIO_SELECTED = $( iso_volid_to_path " $VIRTIO_VOLID " )
2025-05-01 23:35:19 +02:00
else
msg_warn " $( translate "No VirtIO ISO selected. Please choose again." ) "
continue
fi
;;
esac
2026-05-14 14:45:45 +02:00
if [[ -n " $VIRTIO_VOLID " || -f " $VIRTIO_SELECTED " ]] ; then
mount_iso_to_vm " $VMID " " $VIRTIO_SELECTED " "ide3" " $VIRTIO_VOLID "
2025-05-01 23:35:19 +02:00
else
msg_warn " $( translate "VirtIO ISO not found after selection." ) "
fi
break
done
fi
2026-04-05 11:24:08 +02:00
local BOOT_FINAL = ""
if [[ -n " $BOOT_ORDER " ]] ; then
BOOT_FINAL = " $BOOT_ORDER "
fi
2026-05-14 14:45:45 +02:00
if [[ -n " ${ ISO_VOLID :- } " || -f " ${ ISO_PATH :- } " ]] ; then
2026-04-05 11:24:08 +02:00
BOOT_FINAL = " ${ BOOT_FINAL :+ $BOOT_FINAL ; } ide2"
fi
if [[ -n " $BOOT_FINAL " ]] ; then
qm set " $VMID " -boot order = " $BOOT_FINAL " >/dev/null
msg_ok " $( translate "Boot order set to" ) $BOOT_FINAL "
fi
2025-05-01 23:35:19 +02:00
2025-05-07 22:55:35 +02:00
HTML_DESC = "<div align='center'>
<table style='width: 100%; border-collapse: collapse;'>
<tr>
<td style='width: 100px; vertical-align: middle;'>
<img src='https://raw.githubusercontent.com/MacRimi/ProxMenux/main/images/logo_desc.png' alt='ProxMenux Logo' style='height: 100px;'>
</td>
<td style='vertical-align: middle;'>
2025-05-07 23:11:50 +02:00
<h1 style='margin: 0;'> $HN VM</h1>
2025-05-07 22:55:35 +02:00
<p style='margin: 0;'>Created with ProxMenux</p>
</td>
</tr>
</table>
<p>
2025-10-20 20:22:31 +02:00
<a href='https://macrimi.github.io/ProxMenux/docs/create-vm' target='_blank'><img src='https://img.shields.io/badge/📚_Docs-blue' alt='Docs'></a>
2026-04-05 11:24:08 +02:00
<a href='https://github.com/MacRimi/ProxMenux/blob/main/scripts/menus/create_vm_menu.sh' target='_blank'><img src='https://img.shields.io/badge/💻_Code-green' alt='Code'></a>
2025-05-07 22:55:35 +02:00
<a href='https://ko-fi.com/macrimi' target='_blank'><img src='https://img.shields.io/badge/☕_Ko--fi-red' alt='Ko-fi'></a>
</p>
<div>
${ DISK_INFO }
</div>
</div>"
msg_info " $( translate "Setting VM description" ) "
if ! qm set " $VMID " -description " $HTML_DESC " >/dev/null 2>& 1; then
msg_error " $( translate "Failed to set VM description" ) "
else
msg_ok " $( translate "VM description configured" ) "
fi
2025-05-01 23:35:19 +02:00
2026-04-05 11:24:08 +02:00
if [[ " ${ WIZARD_ADD_GPU :- no } " == "yes" && " $START_VM " == "yes" ]] ; then
msg_warn " $( translate "Auto-start was skipped because GPU passthrough setup was requested." ) "
msg_warn " $( translate "After completing GPU setup, start the VM manually when the host is ready." ) "
START_VM = "no"
fi
2025-05-07 23:11:50 +02:00
2025-05-01 23:35:19 +02:00
if [[ " $START_VM " == "yes" ]] ; then
qm start " $VMID "
msg_ok " $( translate "VM started" ) "
fi
configure_guest_agent
2025-05-02 15:41:27 +02:00
2026-04-05 11:24:08 +02:00
if [[ " ${ WIZARD_ADD_GPU :- no } " == "yes" ]] ; then
WIZARD_GPU_RESULT = "cancelled"
run_gpu_passthrough_wizard
2026-04-06 18:40:57 +02:00
local GPU_WIZARD_APPLIED = "no"
local GPU_WIZARD_REBOOT_REQUIRED = "no"
case " $WIZARD_GPU_RESULT " in
applied)
GPU_WIZARD_APPLIED = "yes"
;;
applied_reboot_required)
GPU_WIZARD_APPLIED = "yes"
GPU_WIZARD_REBOOT_REQUIRED = "yes"
;;
esac
2026-04-05 11:24:08 +02:00
if [[ " ${ VM_WIZARD_CAPTURE_ACTIVE :- 0 } " -eq 1 ]] ; then
stop_spinner
exec 1>& 8
exec 8>& -
VM_WIZARD_CAPTURE_ACTIVE = 0
show_proxmenux_logo
cat " $VM_WIZARD_CAPTURE_FILE "
rm -f " $VM_WIZARD_CAPTURE_FILE "
VM_WIZARD_CAPTURE_FILE = ""
fi
2026-04-06 18:40:57 +02:00
if [[ " $GPU_WIZARD_APPLIED " == "yes" ]] ; then
2026-04-05 11:24:08 +02:00
msg_success " $( translate "VM creation completed with GPU passthrough configured." ) "
2026-04-06 18:40:57 +02:00
if [[ " $GPU_WIZARD_REBOOT_REQUIRED " == "yes" ]] ; then
msg_warn " $( translate "Host VFIO configuration changed (initramfs updated). Reboot required before starting the VM." ) "
fi
2026-04-05 11:24:08 +02:00
elif [[ " $WIZARD_GPU_RESULT " == "no_gpu" ]] ; then
msg_success " $( translate "VM creation completed. GPU passthrough was skipped (no compatible GPU detected)." ) "
else
msg_success " $( translate "VM creation completed. GPU passthrough was not applied." ) "
fi
if [[ " $OS_TYPE " == "2" ]] ; then
echo -e " ${ TAB } $( translate "Next Steps:" ) "
echo -e " ${ TAB } 1. $( translate "Start the VM to begin Windows installation from the mounted ISO." ) "
echo -e " ${ TAB } 2. $( translate "When asked to select a disk, click Load Driver and load the VirtIO drivers." ) "
echo -e " ${ TAB } $( translate "Required if using a VirtIO or SCSI disk." ) "
echo -e " ${ TAB } 3. $( translate "Also install the VirtIO network driver during setup to enable network access." ) "
echo -e " ${ TAB } 4. $( translate "Continue the Windows installation as usual." ) "
echo -e " ${ TAB } 5. $( translate "Once installed, open the VirtIO ISO and run the installer to complete driver setup." ) "
echo -e " ${ TAB } 6. $( translate "Reboot the VM to complete the driver installation." ) "
2026-04-06 18:40:57 +02:00
if [[ " $GPU_WIZARD_APPLIED " == "yes" ]] ; then
2026-04-05 11:24:08 +02:00
echo -e " ${ TAB } - $( translate "If you want to use a physical monitor on the passthrough GPU:" ) "
echo -e " ${ TAB } • $( translate "First install the GPU drivers inside the guest and verify remote access (RDP/SSH)." ) "
echo -e " ${ TAB } • $( translate "Then change the VM display to none (vga: none) when the guest is stable." ) "
echo -e " ${ TAB } • $( translate "If passthrough fails on Windows: install RadeonResetBugFix." ) "
fi
echo -e
elif [[ " $OS_TYPE " == "3" ]] ; then
echo -e " ${ TAB }${ GN } $( translate "Recommended: Install the QEMU Guest Agent in the VM" ) ${ CL } "
echo -e " ${ TAB } $( translate "Run the following inside the VM:" ) "
echo -e " ${ TAB } apt install qemu-guest-agent -y && systemctl enable --now qemu-guest-agent"
2026-04-06 18:40:57 +02:00
if [[ " $GPU_WIZARD_APPLIED " == "yes" ]] ; then
2026-04-05 11:24:08 +02:00
echo -e " ${ TAB } - $( translate "If you want to use a physical monitor on the passthrough GPU:" ) "
echo -e " ${ TAB } • $( translate "First install the GPU drivers inside the guest and verify remote access (RDP/SSH)." ) "
echo -e " ${ TAB } • $( translate "Then change the VM display to none (vga: none) when the guest is stable." ) "
fi
echo -e
fi
2026-04-06 18:40:57 +02:00
local HOST_REBOOT_REQUIRED = "no"
2026-04-12 20:32:34 +02:00
local REBOOT_REASONS = ""
2026-04-06 17:16:26 +02:00
if [[ " ${ VM_STORAGE_IOMMU_PENDING_REBOOT :- 0 } " == "1" ]] ; then
2026-04-06 18:40:57 +02:00
HOST_REBOOT_REQUIRED = "yes"
2026-04-12 20:32:34 +02:00
msg_ok " $( translate "IOMMU has been enabled — a system reboot is required" ) "
REBOOT_REASONS += " $( translate "IOMMU has been enabled on this system." ) \n"
2026-04-06 17:16:26 +02:00
fi
2026-04-06 18:40:57 +02:00
if [[ " $GPU_WIZARD_REBOOT_REQUIRED " == "yes" ]] ; then
HOST_REBOOT_REQUIRED = "yes"
2026-04-12 20:32:34 +02:00
REBOOT_REASONS += " $( translate "GPU passthrough changes require a host reboot." ) \n"
2026-04-06 18:40:57 +02:00
fi
if [[ " $HOST_REBOOT_REQUIRED " == "yes" ]] ; then
2026-04-12 20:32:34 +02:00
echo ""
if whiptail --title " $( translate "Reboot Required" ) " --yesno \
"\n ${ REBOOT_REASONS } \n $( translate "A host reboot is required before starting the VM. Reboot now?" ) " 13 78; then
2026-04-06 18:40:57 +02:00
msg_warn " $( translate "Rebooting the system..." ) "
reboot
2026-04-12 20:32:34 +02:00
else
echo ""
msg_info2 " $( translate "To use the VM without issues, the host must be restarted before starting it." ) "
msg_info2 " $( translate "Do not start the VM until the system has been rebooted." ) "
2026-04-06 18:40:57 +02:00
fi
fi
2026-04-05 11:24:08 +02:00
msg_success " $( translate "Press Enter to return to the main menu..." ) "
read -r
bash " $LOCAL_SCRIPTS /menus/create_vm_menu.sh"
exit 0
fi
msg_success " $( translate "VM creation completed" ) "
2025-05-02 16:30:00 +02:00
if [[ " $OS_TYPE " == "2" ]] ; then
2026-04-05 11:24:08 +02:00
echo -e " ${ TAB } $( translate "Next Steps:" ) "
2025-05-02 15:41:27 +02:00
echo -e " ${ TAB } 1. $( translate "Start the VM to begin Windows installation from the mounted ISO." ) "
echo -e " ${ TAB } 2. $( translate "When asked to select a disk, click Load Driver and load the VirtIO drivers." ) "
echo -e " ${ TAB } $( translate "Required if using a VirtIO or SCSI disk." ) "
echo -e " ${ TAB } 3. $( translate "Also install the VirtIO network driver during setup to enable network access." ) "
echo -e " ${ TAB } 4. $( translate "Continue the Windows installation as usual." ) "
echo -e " ${ TAB } 5. $( translate "Once installed, open the VirtIO ISO and run the installer to complete driver setup." ) "
echo -e " ${ TAB } 6. $( translate "Reboot the VM to complete the driver installation." ) "
echo -e
2025-05-02 16:30:00 +02:00
elif [[ " $OS_TYPE " == "3" ]] ; then
2025-05-02 15:41:27 +02:00
echo -e " ${ TAB }${ GN } $( translate "Recommended: Install the QEMU Guest Agent in the VM" ) ${ CL } "
echo -e " ${ TAB } $( translate "Run the following inside the VM:" ) "
2026-04-05 11:24:08 +02:00
echo -e " ${ TAB } apt install qemu-guest-agent -y && systemctl enable --now qemu-guest-agent"
2025-05-02 15:41:27 +02:00
echo -e
fi
msg_success " $( translate "Press Enter to return to the main menu..." ) "
read -r
2025-11-03 02:11:15 +00:00
bash " $LOCAL_SCRIPTS /menus/create_vm_menu.sh"
2025-05-09 19:48:17 +02:00
exit 0
2025-05-02 15:41:27 +02:00
2025-05-01 23:35:19 +02:00
}