@@ -1,5 +1,5 @@
# Copyright (c) 2021-2026 community-scripts ORG
# License: MIT | https://git.community-scripts.org /community-scripts/ProxmoxVE/raw/branch/ main/LICENSE
# License: MIT | https://raw.githubusercontent.com /community-scripts/ProxmoxVE/main/LICENSE
set -euo pipefail
SPINNER_PID = ""
@@ -14,9 +14,18 @@ declare -A MSG_INFO_SHOWN
[ [ -n " ${ _CORE_FUNC_LOADED :- } " ] ] && return
_CORE_FUNC_LOADED = 1
COMMUNITY_SCRIPTS_URL = " ${ COMMUNITY_SCRIPTS_URL :- https : //git.community-scripts.org/community-scripts/ProxmoxVE/raw/branch/main } "
load_api_functions( ) {
if ! declare -f post_to_api_vm >/dev/null 2>& 1; then
source /dev/stdin <<< $( curl -fsSL " $COMMUNITY_SCRIPTS_URL /misc/api.func " )
fi
}
load_functions( ) {
[ [ -n " ${ __FUNCTIONS_LOADED :- } " ] ] && return
__FUNCTIONS_LOADED = 1
load_api_functions
color
formatting
icons
@@ -31,18 +40,24 @@ load_functions() {
arch_check
}
load_cloud_init_functions( ) {
if ! declare -f setup_cloud_init >/dev/null 2>& 1; then
source <( curl -fsSL " $COMMUNITY_SCRIPTS_URL /misc/cloud-init.func " ) 2>/dev/null || true
fi
}
# Function to download & save header files
get_header( ) {
local app_name = $( echo " ${ APP ,, } " | tr ' ' '-' )
local app_type = ${ APP_TYPE :- vm }
local header_url = " https://git.community-scripts.org /community-scripts/ProxmoxVE/raw/branch/ main/ ${ app_type } /headers/ ${ app_name } "
local header_url = " https://raw.githubusercontent.com /community-scripts/ProxmoxVE/main/ ${ app_type } /headers/ ${ app_name } "
local local_header_path = " /usr/local/community-scripts/headers/ ${ app_type } / ${ app_name } "
mkdir -p " $( dirname " $local_header_path " ) "
if [ ! -s " $local_header_path " ] ; then
if ! curl -fsSL " $header_url " -o " $local_header_path " ; then
return 250
return 1
fi
fi
@@ -98,6 +113,7 @@ icons() {
DNSOK = "✔️ "
DNSFAIL = " ${ TAB } ✖️ ${ TAB } "
INFO = " ${ TAB } 💡 ${ TAB } ${ CL } "
CLOUD = " ${ TAB } ☁️ ${ TAB } ${ CL } "
OS = " ${ TAB } 🖥️ ${ TAB } ${ CL } "
OSVERSION = " ${ TAB } 🌟 ${ TAB } ${ CL } "
CONTAINERTYPE = " ${ TAB } 📦 ${ TAB } ${ CL } "
@@ -188,18 +204,32 @@ silent() {
trap 'error_handler' ERR
if [ [ $rc -ne 0 ] ] ; then
# Return instead of exit so that callers can use `$STD cmd || true`
# When no || is used, set -e + ERR trap catches it via error_handler()
export _SILENT_FAILED_RC = " $rc "
export _SILENT_FAILED_CMD = " $cmd "
export _SILENT_FAILED_LINE = " $caller_line "
export _SILENT_FAILED_LOG = " $logfile "
# Source explain_exit_code if needed
if ! declare -f explain_exit_code >/dev/null 2>& 1; then
source <( curl -fsSL " $COMMUNITY_SCRIPTS_URL /misc/error_handler.func " ) 2>/dev/null || true
fi
return " $rc "
local explanation = " "
if declare -f explain_exit_code >/dev/null 2>& 1; then
explanation = " $( explain_exit_code " $rc " ) "
fi
printf "\e[?25h"
if [ [ -n " $explanation " ] ] ; then
msg_error " in line ${ caller_line } : exit code ${ rc } ( ${ explanation } ) "
else
msg_error " in line ${ caller_line } : exit code ${ rc } "
fi
msg_custom "→" " ${ YWB } " " ${ cmd } "
if [ [ -s " $logfile " ] ] ; then
echo -e " \n ${ TAB } --- Last 20 lines of log --- "
tail -n 20 " $logfile "
echo -e " ${ TAB } ----------------------------\n "
fi
exit " $rc "
fi
# Clear stale flags on success
unset _SILENT_FAILED_RC _SILENT_FAILED_CMD _SILENT_FAILED_LINE _SILENT_FAILED_LOG 2>/dev/null || true
}
# ------------------------------------------------------------------------------
@@ -230,7 +260,7 @@ curl_handler() {
if [ [ -z " $url " ] ] ; then
msg_error "no valid url or option entered for curl_handler"
exit 64
exit 1
fi
$STD msg_info " Fetching: $url "
@@ -259,7 +289,7 @@ curl_handler() {
rm -f /tmp/curl_error.log
fi
__curl_err_handler " $exit_code " " $url " " $curl_stderr "
exit " $exit_code "
exit 1 # hard exit if exit_code is not 0
fi
$STD printf " \r\033[K ${ INFO } ${ YW } Retry $attempt / $max_retries in ${ delay } s... ${ CL } " >& 2
@@ -302,7 +332,7 @@ __curl_err_handler() {
esac
[ [ -n " $curl_msg " ] ] && printf "%s\n" " $curl_msg " >& 2
exit " $exit_code "
exit 1
}
# ------------------------------------------------------------------------------
@@ -317,7 +347,7 @@ shell_check() {
msg_error "Your default shell is currently not set to Bash. To use these scripts, please switch to the Bash shell."
echo -e "\nExiting..."
sleep 2
exit 103
exit
fi
}
@@ -338,11 +368,11 @@ clear_line() {
#
# - Determines if script should run in verbose mode
# - Checks VERBOSE and var_verbose variables
# - Note: Non-TTY (pipe) scenarios are handled separately in msg_info( )
# - Also returns true if not running in TTY (pipe/redirect scenario )
# ------------------------------------------------------------------------------
is_verbose_mode( ) {
local verbose = " ${ VERBOSE :- ${ var_verbose :- no } } "
[ [ " $verbose " != "no" ] ]
[ [ " $verbose " != "no" || ! -t 2 ] ]
}
### dev spinner ###
@@ -481,6 +511,20 @@ msg_debug() {
fi
}
error_handler( ) {
local exit_code = " $? "
local line_number = " ${ 1 :- unknown } "
local command = " ${ 2 :- unknown } "
if declare -f post_update_to_api >/dev/null 2>& 1; then
post_update_to_api "failed" " $exit_code "
fi
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 "
cleanup_vmid
}
# Displays error message and immediately terminates script
fatal( ) {
msg_error " $1 "
@@ -516,9 +560,13 @@ cleanup_vmid() {
cleanup( ) {
local exit_code = $?
stop_spinner
if [ [ " $( dirs -p | wc -l) " -gt 1 ] ] ; then
popd >/dev/null || true
fi
if [ [ -n " ${ TEMP_DIR :- } " && -d " $TEMP_DIR " ] ] ; then
rm -rf " $TEMP_DIR "
fi
# Report final telemetry status if post_to_api_vm was called but no update was sent
if [ [ " ${ POST_TO_API_DONE :- } " = = "true" && " ${ POST_UPDATE_DONE :- } " != "true" ] ] ; then
if declare -f post_update_to_api >/dev/null 2>& 1; then
@@ -538,18 +586,37 @@ check_root() {
msg_error "Please run this script as root."
echo -e "\nExiting..."
sleep 2
exit 104
exit
fi
}
pve_check( ) {
if ! pveversion | grep -Eq "pve-manager/(8\.[1-4]|9\.[0-2])(\.[0-9]+)*" ; then
msg_error "This version of Proxmox Virtual Environment is not supported "
echo -e "Requires Proxmox Virtual Environment Version 8.1 - 8.4 or 9.0 - 9.2."
echo -e "Exiting..."
sleep 2
exit 105
local pve_ ver
pve_ver = " $( pveversion | awk -F '/' '{print $2}' | awk -F '-' '{print $1}' ) "
if [ [ " $pve_ver " = ~ ^8\. ( [ 0-9] +) ] ] ; then
local minor = " ${ BASH_REMATCH [1] } "
if ( ( minor < 0 || minor > 9) ) ; then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 8.0 – 8.9"
exit 105
fi
return 0
fi
if [ [ " $pve_ver " = ~ ^9\. ( [ 0-9] +) ] ] ; then
local minor = " ${ BASH_REMATCH [1] } "
if ( ( minor < 0 || minor > 2) ) ; then
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported: Proxmox VE version 9.0 – 9.2"
exit 105
fi
return 0
fi
msg_error "This version of Proxmox VE is not supported."
msg_error "Supported versions: Proxmox VE 8.0 – 8.9 or 9.0 – 9.2"
exit 105
}
arch_check( ) {
@@ -558,50 +625,487 @@ arch_check() {
echo -e " \n ${ YWB } Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n "
echo -e "Exiting..."
sleep 2
exit 106
exit
fi
}
ssh_check( ) {
if command -v pveversion >/dev/null 2>& 1 && [ -n " ${ SSH_CLIENT :- } " ] ; then
if whiptail --backtitle "Proxmox VE Helper Scripts" --defaultno --title "SSH DETECTED" --yesno "It's suggested to use the Proxmox shell instead of SSH, since SSH can create issues while gathering variables. Would you like to proceed with using SSH?" 10 62; then
:
else
clear
exit
fi
fi
}
exit_script( ) {
clear
echo -e " \n ${ CROSS } ${ RD } User exited script ${ CL } \n "
exit 0
exit
}
sanitize_vm_hostname( ) {
local hostname = " ${ 1 ,, } "
hostname = $( echo " $hostname " | tr -cs 'a-z0-9-' '-' | sed 's/^-//;s/-$//' )
echo " ${ hostname : 0 : 63 } "
}
vm_confirm_new_vm( ) {
local title = " $1 "
local message = " $2 "
local height = " ${ 3 :- 10 } "
local width = " ${ 4 :- 58 } "
whiptail --backtitle "Proxmox VE Helper Scripts" --title " $title " --yesno " $message " " $height " " $width "
}
vm_choose_settings_mode( ) {
local message = " ${ 1 :- Use Default Settings? } "
local height = " ${ 2 :- 10 } "
local width = " ${ 3 :- 58 } "
whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno " $message " --no-button Advanced " $height " " $width "
}
vm_confirm_advanced_settings( ) {
local message = " $1 "
local height = " ${ 2 :- 10 } "
local width = " ${ 3 :- 58 } "
whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno " $message " --no-button Do-Over " $height " " $width "
}
vm_prompt_vmid( ) {
local default_vmid = " ${ 1 :- $( get_valid_nextid) } "
while true; do
if VMID = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 " $default_vmid " --title "VIRTUAL MACHINE ID" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $VMID " ] ; then
VMID = $( get_valid_nextid)
fi
if pct status " $VMID " & >/dev/null || qm status " $VMID " & >/dev/null; then
echo -e " ${ CROSS } ${ RD } ID $VMID is already in use ${ CL } "
sleep 2
continue
fi
echo -e " ${ CONTAINERID } ${ BOLD } ${ DGN } Virtual Machine ID: ${ BGN } $VMID ${ CL } "
break
else
exit_script
fi
done
}
vm_apply_machine_type( ) {
local machine_type = " ${ 1 :- i440fx } "
if [ " $machine_type " = "q35" ] ; then
MACHINE_TYPE = "q35"
FORMAT = ""
MACHINE = " -machine q35"
else
MACHINE_TYPE = "i440fx"
FORMAT = ",efitype=4m"
MACHINE = ""
fi
}
vm_machine_type_label( ) {
case " ${ 1 :- i440fx } " in
q35)
echo "Q35 (Modern)"
; ;
*)
echo "i440fx"
; ;
esac
}
vm_prompt_machine_type( ) {
local default_machine = " ${ 1 :- i440fx } "
local i440fx_default = "ON"
local q35_default = "OFF"
local machine_choice
if [ " $default_machine " = "q35" ] ; then
i440fx_default = "OFF"
q35_default = "ON"
fi
if machine_choice = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
"i440fx" "Machine i440fx" " $i440fx_default " \
"q35" "Machine q35" " $q35_default " \
3>& 1 1>& 2 2>& 3) ; then
vm_apply_machine_type " $machine_choice "
echo -e " ${ CONTAINERTYPE } ${ BOLD } ${ DGN } Machine Type: ${ BGN } $( vm_machine_type_label " $MACHINE_TYPE " ) ${ CL } "
else
exit_script
fi
}
vm_prompt_cloud_init( ) {
local default_user = " ${ 1 :- root } "
USE_CLOUD_INIT = "no"
load_cloud_init_functions
if ! declare -f configure_cloud_init_interactive >/dev/null 2>& 1; then
echo -e " ${ CLOUD } ${ BOLD } ${ DGN } Cloud-Init: ${ BGN } unavailable ${ CL } "
return 1
fi
configure_cloud_init_interactive " $default_user " || true
USE_CLOUD_INIT = " ${ CLOUDINIT_ENABLE :- no } "
echo -e " ${ CLOUD } ${ BOLD } ${ DGN } Cloud-Init: ${ BGN } ${ USE_CLOUD_INIT } ${ CL } "
if [ " $USE_CLOUD_INIT " = "yes" ] && declare -f configure_cloudinit_ssh_keys >/dev/null 2>& 1; then
configure_cloudinit_ssh_keys || true
fi
return 0
}
vm_prompt_disk_size( ) {
local default_size = " ${ 1 :- 8G } "
local prompt_message = " ${ 2 :- Set Disk Size in GiB (e.g., 10, 20) } "
if DISK_SIZE = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox " $prompt_message " 8 58 " $default_size " --title "DISK SIZE" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
DISK_SIZE = $( echo " $DISK_SIZE " | tr -d ' ' )
if [ [ " $DISK_SIZE " = ~ ^[ 0-9] +$ ] ] ; then
DISK_SIZE = " ${ DISK_SIZE } G "
echo -e " ${ DISKSIZE } ${ BOLD } ${ DGN } Disk Size: ${ BGN } $DISK_SIZE ${ CL } "
elif [ [ " $DISK_SIZE " = ~ ^[ 0-9] +G$ ] ] ; then
echo -e " ${ DISKSIZE } ${ BOLD } ${ DGN } Disk Size: ${ BGN } $DISK_SIZE ${ CL } "
else
echo -e " ${ DISKSIZE } ${ BOLD } ${ RD } Invalid Disk Size. Please use a number (e.g., 10 or 10G). ${ CL } "
exit_script
fi
else
exit_script
fi
}
vm_prompt_disk_cache( ) {
local default_cache = " ${ 1 :- none } "
local none_default = "ON"
local write_default = "OFF"
local cache_choice
if [ " $default_cache " = "writethrough" ] ; then
none_default = "OFF"
write_default = "ON"
fi
if cache_choice = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "None (Default)" " $none_default " \
"1" "Write Through" " $write_default " \
3>& 1 1>& 2 2>& 3) ; then
if [ " $cache_choice " = "1" ] ; then
DISK_CACHE = "cache=writethrough,"
echo -e " ${ DISKSIZE } ${ BOLD } ${ DGN } Disk Cache: ${ BGN } Write Through ${ CL } "
else
DISK_CACHE = ""
echo -e " ${ DISKSIZE } ${ BOLD } ${ DGN } Disk Cache: ${ BGN } None ${ CL } "
fi
else
exit_script
fi
}
vm_prompt_hostname( ) {
local default_hostname = " ${ 1 :- vm } "
local adjusted_hostname
local input_hostname
if input_hostname = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 " $default_hostname " --title "HOSTNAME" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $input_hostname " ] ; then
HN = " $default_hostname "
else
adjusted_hostname = $( sanitize_vm_hostname " $input_hostname " )
HN = " ${ adjusted_hostname :- $default_hostname } "
if [ " $HN " != " ${ input_hostname ,, } " ] ; then
whiptail --backtitle "Proxmox VE Helper Scripts" --title "HOSTNAME ADJUSTED" --msgbox " Invalid characters detected. Hostname has been adjusted to:\n\n $HN " 10 58
fi
fi
echo -e " ${ HOSTNAME } ${ BOLD } ${ DGN } Hostname: ${ BGN } $HN ${ CL } "
else
exit_script
fi
}
vm_prompt_cpu_model( ) {
local default_model = " ${ 1 :- kvm64 } "
local kvm_default = "ON"
local host_default = "OFF"
local cpu_choice
if [ " $default_model " = "host" ] ; then
kvm_default = "OFF"
host_default = "ON"
fi
if cpu_choice = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
"0" "KVM64 (Default)" " $kvm_default " \
"1" "Host" " $host_default " \
3>& 1 1>& 2 2>& 3) ; then
if [ " $cpu_choice " = "1" ] ; then
CPU_TYPE = " -cpu host"
echo -e " ${ OS } ${ BOLD } ${ DGN } CPU Model: ${ BGN } Host ${ CL } "
else
CPU_TYPE = ""
echo -e " ${ OS } ${ BOLD } ${ DGN } CPU Model: ${ BGN } KVM64 ${ CL } "
fi
else
exit_script
fi
}
vm_prompt_cpu_cores( ) {
local default_cores = " ${ 1 :- 2 } "
while true; do
if CORE_COUNT = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 " $default_cores " --title "CORE COUNT" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $CORE_COUNT " ] ; then
CORE_COUNT = " $default_cores "
fi
if [ [ " $CORE_COUNT " = ~ ^[ 1-9] [ 0-9] *$ ] ] ; then
echo -e " ${ CPUCORE } ${ BOLD } ${ DGN } CPU Cores: ${ BGN } $CORE_COUNT ${ CL } "
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "CPU Cores must be a positive integer (e.g., 2)." 8 58
else
exit_script
fi
done
}
vm_prompt_ram( ) {
local default_ram = " ${ 1 :- 2048 } "
while true; do
if RAM_SIZE = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 " $default_ram " --title "RAM" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $RAM_SIZE " ] ; then
RAM_SIZE = " $default_ram "
fi
if [ [ " $RAM_SIZE " = ~ ^[ 1-9] [ 0-9] *$ ] ] ; then
echo -e " ${ RAMSIZE } ${ BOLD } ${ DGN } RAM Size: ${ BGN } $RAM_SIZE ${ CL } "
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "RAM Size must be a positive integer in MiB (e.g., 2048)." 8 58
else
exit_script
fi
done
}
vm_prompt_bridge( ) {
local default_bridge = " ${ 1 :- vmbr0 } "
if BRG = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 " $default_bridge " --title "BRIDGE" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $BRG " ] ; then
BRG = " $default_bridge "
fi
echo -e " ${ BRIDGE } ${ BOLD } ${ DGN } Bridge: ${ BGN } $BRG ${ CL } "
else
exit_script
fi
}
vm_prompt_mac( ) {
local default_mac = " ${ 1 :- $GEN_MAC } "
local input_mac
while true; do
if input_mac = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 " $default_mac " --title "MAC ADDRESS" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $input_mac " ] ; then
MAC = " $default_mac "
echo -e " ${ MACADDRESS } ${ BOLD } ${ DGN } MAC Address: ${ BGN } $MAC ${ CL } "
break
fi
if [ [ " $input_mac " = ~ ^( [ 0-9A-Fa-f] { 2} :) { 5} [ 0-9A-Fa-f] { 2} $ ] ] ; then
MAC = " $input_mac "
echo -e " ${ MACADDRESS } ${ BOLD } ${ DGN } MAC Address: ${ BGN } $MAC ${ CL } "
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "Invalid MAC address format. Use XX:XX:XX:XX:XX:XX (e.g., AA:BB:CC:DD:EE:FF)." 8 58
else
exit_script
fi
done
}
vm_prompt_vlan( ) {
local default_vlan = " ${ 1 :- } "
local input_vlan
while true; do
if input_vlan = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan (leave blank for default)" 8 58 " $default_vlan " --title "VLAN" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $input_vlan " ] ; then
VLAN = ""
echo -e " ${ VLANTAG } ${ BOLD } ${ DGN } VLAN: ${ BGN } Default ${ CL } "
break
fi
if [ [ " $input_vlan " = ~ ^[ 0-9] +$ ] ] && [ " $input_vlan " -ge 1 ] && [ " $input_vlan " -le 4094 ] ; then
VLAN = " ,tag= $input_vlan "
echo -e " ${ VLANTAG } ${ BOLD } ${ DGN } VLAN: ${ BGN } $input_vlan ${ CL } "
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "VLAN must be a number between 1 and 4094, or leave blank for default." 8 58
else
exit_script
fi
done
}
vm_prompt_mtu( ) {
local default_mtu = " ${ 1 :- } "
local input_mtu
while true; do
if input_mtu = $( whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 " $default_mtu " --title "MTU SIZE" --cancel-button Exit-Script 3>& 1 1>& 2 2>& 3) ; then
if [ -z " $input_mtu " ] ; then
MTU = ""
echo -e " ${ DEFAULT } ${ BOLD } ${ DGN } Interface MTU Size: ${ BGN } Default ${ CL } "
break
fi
if [ [ " $input_mtu " = ~ ^[ 0-9] +$ ] ] && [ " $input_mtu " -ge 576 ] && [ " $input_mtu " -le 65520 ] ; then
MTU = " ,mtu= $input_mtu "
echo -e " ${ DEFAULT } ${ BOLD } ${ DGN } Interface MTU Size: ${ BGN } $input_mtu ${ CL } "
break
fi
whiptail --backtitle "Proxmox VE Helper Scripts" --title "INVALID INPUT" --msgbox "MTU Size must be a number between 576 and 65520, or leave blank for default." 8 58
else
exit_script
fi
done
}
vm_prompt_start_vm( ) {
local default_start = " ${ 1 :- yes } "
local default_flag = ( )
if [ " $default_start " = "no" ] ; then
default_flag = ( --defaultno)
fi
if whiptail --backtitle "Proxmox VE Helper Scripts" " ${ default_flag [@] } " --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58; then
START_VM = "yes"
else
START_VM = "no"
fi
echo -e " ${ GATEWAY } ${ BOLD } ${ DGN } Start VM when completed: ${ BGN } ${ START_VM } ${ CL } "
}
vm_apply_storage_layout( ) {
local storage_type = " $1 "
case $storage_type in
nfs | dir | cifs)
DISK_EXT = ".qcow2"
DISK_REF = " $VMID / "
DISK_IMPORT_FORMAT = "qcow2"
THIN = ""
; ;
btrfs)
DISK_EXT = ".raw"
DISK_REF = " $VMID / "
DISK_IMPORT_FORMAT = "raw"
FORMAT = ",efitype=4m"
THIN = ""
; ;
*)
DISK_EXT = ""
DISK_REF = ""
DISK_IMPORT_FORMAT = "raw"
; ;
esac
}
vm_select_storage( ) {
local hostname = " ${ 1 :- ${ HN :- vm } } "
local storage_menu = ( )
local msg_max_length = 0
local line tag type free item
local offset = 2
local valid_storage
msg_info "Validating Storage"
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)}' )
item = " Type: $type Free: $free "
if [ [ $(( ${# item } + offset)) -gt $msg_max_length ] ] ; then
msg_max_length = $(( ${# item } + offset))
fi
storage_menu += ( " $tag " " $item " "OFF" )
done < <( pvesm status -content images | awk 'NR>1' )
valid_storage = $( pvesm status -content images | awk 'NR>1' )
if [ -z " $valid_storage " ] ; then
msg_error "Unable to detect a valid storage location."
exit
elif [ $(( ${# storage_menu [@] } / 3 )) -eq 1 ] ; then
STORAGE = ${ storage_menu [0] }
else
if [ -n " ${ SPINNER_PID :- } " ] && ps -p " $SPINNER_PID " >/dev/null 2>& 1; then
kill " $SPINNER_PID " >/dev/null 2>& 1 || true
SPINNER_ACTIVE = 0
printf "\r\e[2K" >& 2
fi
while [ -z " ${ STORAGE : +x } " ] ; do
STORAGE = $( whiptail --backtitle "Proxmox VE Helper Scripts" --title "Storage Pools" --radiolist \
" Which storage pool would you like to use for ${ hostname } ?\nTo make a selection, use the Spacebar.\n " \
16 $(( $msg_max_length + 23 )) 6 \
" ${ storage_menu [@] } " 3>& 1 1>& 2 2>& 3)
done
fi
msg_ok " Using ${ CL } ${ BL } $STORAGE ${ CL } ${ GN } for Storage Location. "
msg_ok " Virtual Machine ID is ${ CL } ${ BL } $VMID ${ CL } . "
STORAGE_TYPE = $( pvesm status -storage " $STORAGE " | awk 'NR>1 {print $2}' )
vm_apply_storage_layout " $STORAGE_TYPE "
}
vm_define_disk_references( ) {
local disk_count = " ${ 1 :- 2 } "
local i disk_name
for ( ( i = 0; i < disk_count; i++) ) ; do
disk_name = " vm- ${ VMID } -disk- ${ i } ${ DISK_EXT :- } "
printf -v " DISK ${ i } " '%s' " $disk_name "
printf -v " DISK ${ i } _REF " '%s' " ${ STORAGE } : ${ DISK_REF :- } ${ disk_name } "
done
}
check_hostname_conflict( ) {
local hostname = " $1 "
if qm list | awk '{print $2}' | grep -qx " $hostname " ; then
msg_error " Hostname $hostname already in use by another VM. "
exit 206
exit 1
fi
}
set_description( ) {
local app_name script_slug script_url donate_url
app_name = $( echo " ${ APP ,, } " | tr ' ' '-' )
script_slug = " ${ SCRIPT_SLUG :- ${ app_name } } "
script_slug = " $( echo " $script_slug " | tr '[:upper:]' '[:lower:]' | tr ' ' '-' ) "
script_url = " https://community-scripts.org/scripts/ ${ script_slug } "
donate_url = "https://community-scripts.org/donate"
local description_title = " ${ APP :- ${ NSAPP } VM } "
DESCRIPTION = $(
cat <<EOF
<div align='center'>
<a href='https://community-s cripts.org ' target='_blank' rel='noopener noreferrer'>
<a href='https://Helper-S cripts.com ' target='_blank' rel='noopener noreferrer'>
<img src='https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/misc/images/logo-81x112.png' alt='Logo' style='width:81px;height:112px;'/>
</a>
<h2 style='font-size: 24px; margin: 20px 0;'>${NSAPP} VM </h2>
<h2 style='font-size: 24px; margin: 20px 0;'>${description_title} </h2>
<p style='margin: 16px 0;'>
<a href='${donate_url} ' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/❤️-Sponsoring%20%26%20Donations-FF5E5B' alt='Sponsoring and donations ' />
</a>
</p>
<p style='margin: 12px 0;'>
<a href='${script_url}' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/📦-Open%20Script%20Page-00617f' alt='Open script page' />
<a href='https://ko-fi.com/community_scripts ' target='_blank' rel='noopener noreferrer'>
<img src='https://img.shields.io/badge/☕-Buy us a coffee-blue' alt='spend Coffee ' />
</a>
</p>