The install-docker.sh script is now generated with Portainer installation logic only if INSTALL_PORTAINER is set to 'yes'. The previous placeholder and sed replacement approach has been removed for clarity and maintainability. This change improves script generation and conditional handling for Portainer installation.
991 lines
32 KiB
Bash
991 lines
32 KiB
Bash
#!/usr/bin/env bash
|
||
|
||
# Copyright (c) 2021-2025 community-scripts ORG
|
||
# Author: thost96 (thost96) | Co-Author: michelroegl-brunner
|
||
# License: MIT | https://github.com/community-scripts/ProxmoxVE/raw/main/LICENSE
|
||
|
||
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/api.func)
|
||
# Load Cloud-Init library for VM configuration
|
||
source /dev/stdin <<<$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVED/main/misc/cloud-init.sh) 2>/dev/null || true
|
||
|
||
function header_info() {
|
||
clear
|
||
cat <<"EOF"
|
||
____ __ _ ____ ___
|
||
/ __ \____ _____/ /_____ _____ | | / / |/ /
|
||
/ / / / __ \/ ___/ //_/ _ \/ ___/ | | / / /|_/ /
|
||
/ /_/ / /_/ / /__/ ,< / __/ / | |/ / / / /
|
||
/_____/\____/\___/_/|_|\___/_/ |___/_/ /_/
|
||
|
||
EOF
|
||
}
|
||
header_info
|
||
echo -e "\n Loading..."
|
||
GEN_MAC=02:$(openssl rand -hex 5 | awk '{print toupper($0)}' | sed 's/\(..\)/\1:/g; s/.$//')
|
||
RANDOM_UUID="$(cat /proc/sys/kernel/random/uuid)"
|
||
METHOD=""
|
||
NSAPP="docker-vm"
|
||
var_os="debian"
|
||
var_version="13"
|
||
DISK_SIZE="10G"
|
||
USE_CLOUD_INIT="no"
|
||
INSTALL_PORTAINER="no"
|
||
OS_TYPE=""
|
||
OS_VERSION=""
|
||
|
||
YW=$(echo "\033[33m")
|
||
BL=$(echo "\033[36m")
|
||
RD=$(echo "\033[01;31m")
|
||
BGN=$(echo "\033[4;92m")
|
||
GN=$(echo "\033[1;92m")
|
||
DGN=$(echo "\033[32m")
|
||
CL=$(echo "\033[m")
|
||
|
||
CL=$(echo "\033[m")
|
||
BOLD=$(echo "\033[1m")
|
||
BFR="\\r\\033[K"
|
||
HOLD=" "
|
||
TAB=" "
|
||
|
||
CM="${TAB}✔️${TAB}${CL}"
|
||
CROSS="${TAB}✖️${TAB}${CL}"
|
||
INFO="${TAB}💡${TAB}${CL}"
|
||
OS="${TAB}🖥️${TAB}${CL}"
|
||
CONTAINERTYPE="${TAB}📦${TAB}${CL}"
|
||
DISKSIZE="${TAB}💾${TAB}${CL}"
|
||
CPUCORE="${TAB}🧠${TAB}${CL}"
|
||
RAMSIZE="${TAB}🛠️${TAB}${CL}"
|
||
CONTAINERID="${TAB}🆔${TAB}${CL}"
|
||
HOSTNAME="${TAB}🏠${TAB}${CL}"
|
||
BRIDGE="${TAB}🌉${TAB}${CL}"
|
||
GATEWAY="${TAB}🌐${TAB}${CL}"
|
||
DEFAULT="${TAB}⚙️${TAB}${CL}"
|
||
MACADDRESS="${TAB}🔗${TAB}${CL}"
|
||
VLANTAG="${TAB}🏷️${TAB}${CL}"
|
||
CREATING="${TAB}🚀${TAB}${CL}"
|
||
ADVANCED="${TAB}🧩${TAB}${CL}"
|
||
CLOUD="${TAB}☁️${TAB}${CL}"
|
||
|
||
THIN="discard=on,ssd=1,"
|
||
set -e
|
||
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
|
||
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" "${command}"
|
||
echo -e "\n$error_message\n"
|
||
cleanup_vmid
|
||
}
|
||
|
||
function get_valid_nextid() {
|
||
local try_id
|
||
try_id=$(pvesh get /cluster/nextid)
|
||
while true; do
|
||
if [ -f "/etc/pve/qemu-server/${try_id}.conf" ] || [ -f "/etc/pve/lxc/${try_id}.conf" ]; then
|
||
try_id=$((try_id + 1))
|
||
continue
|
||
fi
|
||
if lvs --noheadings -o lv_name | grep -qE "(^|[-_])${try_id}($|[-_])"; then
|
||
try_id=$((try_id + 1))
|
||
continue
|
||
fi
|
||
break
|
||
done
|
||
echo "$try_id"
|
||
}
|
||
|
||
function cleanup_vmid() {
|
||
if qm status $VMID &>/dev/null; then
|
||
qm stop $VMID &>/dev/null
|
||
qm destroy $VMID &>/dev/null
|
||
fi
|
||
}
|
||
|
||
function cleanup() {
|
||
popd >/dev/null
|
||
post_update_to_api "done" "none"
|
||
rm -rf $TEMP_DIR
|
||
}
|
||
|
||
TEMP_DIR=$(mktemp -d)
|
||
pushd $TEMP_DIR >/dev/null
|
||
if whiptail --backtitle "Proxmox VE Helper Scripts" --title "Docker VM" --yesno "This will create a New Docker VM. Proceed?" 10 58; then
|
||
:
|
||
else
|
||
header_info && echo -e "${CROSS}${RD}User exited script${CL}\n" && exit
|
||
fi
|
||
|
||
function msg_info() {
|
||
local msg="$1"
|
||
echo -ne "${TAB}${YW}${HOLD}${msg}${HOLD}"
|
||
}
|
||
|
||
function msg_ok() {
|
||
local msg="$1"
|
||
echo -e "${BFR}${CM}${GN}${msg}${CL}"
|
||
}
|
||
|
||
function msg_error() {
|
||
local msg="$1"
|
||
echo -e "${BFR}${CROSS}${RD}${msg}${CL}"
|
||
}
|
||
|
||
function spinner() {
|
||
local pid=$1
|
||
local msg="$2"
|
||
local spin='⠋⠙⠹⠸⠼⠴⠦⠧⠇⠏'
|
||
local i=0
|
||
|
||
echo -ne "${TAB}${YW}${msg} "
|
||
while kill -0 $pid 2>/dev/null; do
|
||
i=$(((i + 1) % 10))
|
||
echo -ne "\b${spin:$i:1}"
|
||
sleep 0.1
|
||
done
|
||
echo -ne "\b"
|
||
}
|
||
|
||
function check_root() {
|
||
if [[ "$(id -u)" -ne 0 || $(ps -o comm= -p $PPID) == "sudo" ]]; then
|
||
clear
|
||
msg_error "Please run this script as root."
|
||
echo -e "\nExiting..."
|
||
sleep 2
|
||
exit
|
||
fi
|
||
}
|
||
|
||
# This function checks the version of Proxmox Virtual Environment (PVE) and exits if the version is not supported.
|
||
# Supported: Proxmox VE 8.0.x – 8.9.x and 9.0 – 9.1
|
||
pve_check() {
|
||
local PVE_VER
|
||
PVE_VER="$(pveversion | awk -F'/' '{print $2}' | awk -F'-' '{print $1}')"
|
||
|
||
# Check for Proxmox VE 8.x: allow 8.0–8.9
|
||
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 1
|
||
fi
|
||
PVE_MAJOR=8
|
||
return 0
|
||
fi
|
||
|
||
# Check for Proxmox VE 9.x: allow 9.0–9.1
|
||
if [[ "$PVE_VER" =~ ^9\.([0-9]+) ]]; then
|
||
local MINOR="${BASH_REMATCH[1]}"
|
||
if ((MINOR < 0 || MINOR > 1)); then
|
||
msg_error "This version of Proxmox VE is not yet supported."
|
||
msg_error "Supported: Proxmox VE version 9.0 – 9.1"
|
||
exit 1
|
||
fi
|
||
PVE_MAJOR=9
|
||
return 0
|
||
fi
|
||
|
||
# All other unsupported versions
|
||
msg_error "This version of Proxmox VE is not supported."
|
||
msg_error "Supported versions: Proxmox VE 8.0 – 8.x or 9.0 – 9.1"
|
||
exit 1
|
||
}
|
||
|
||
function arch_check() {
|
||
if [ "$(dpkg --print-architecture)" != "amd64" ]; then
|
||
echo -e "\n ${INFO}${YWB}This script will not work with PiMox! \n"
|
||
echo -e "\n ${YWB}Visit https://github.com/asylumexp/Proxmox for ARM64 support. \n"
|
||
echo -e "Exiting..."
|
||
sleep 2
|
||
exit
|
||
fi
|
||
}
|
||
|
||
function ssh_check() {
|
||
if command -v pveversion >/dev/null 2>&1; then
|
||
if [ -n "${SSH_CLIENT:+x}" ]; 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
|
||
echo "you've been warned"
|
||
else
|
||
clear
|
||
exit
|
||
fi
|
||
fi
|
||
fi
|
||
}
|
||
|
||
function exit-script() {
|
||
clear
|
||
echo -e "\n${CROSS}${RD}User exited script${CL}\n"
|
||
exit
|
||
}
|
||
|
||
function select_os() {
|
||
if OS_CHOICE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "SELECT OS" --radiolist \
|
||
"Choose Operating System for Docker VM" 14 68 4 \
|
||
"debian13" "Debian 13 (Trixie) - Latest" ON \
|
||
"debian12" "Debian 12 (Bookworm) - Stable" OFF \
|
||
"ubuntu2404" "Ubuntu 24.04 LTS (Noble)" OFF \
|
||
"ubuntu2204" "Ubuntu 22.04 LTS (Jammy)" OFF \
|
||
3>&1 1>&2 2>&3); then
|
||
case $OS_CHOICE in
|
||
debian13)
|
||
OS_TYPE="debian"
|
||
OS_VERSION="13"
|
||
OS_CODENAME="trixie"
|
||
OS_DISPLAY="Debian 13 (Trixie)"
|
||
;;
|
||
debian12)
|
||
OS_TYPE="debian"
|
||
OS_VERSION="12"
|
||
OS_CODENAME="bookworm"
|
||
OS_DISPLAY="Debian 12 (Bookworm)"
|
||
;;
|
||
ubuntu2404)
|
||
OS_TYPE="ubuntu"
|
||
OS_VERSION="24.04"
|
||
OS_CODENAME="noble"
|
||
OS_DISPLAY="Ubuntu 24.04 LTS"
|
||
;;
|
||
ubuntu2204)
|
||
OS_TYPE="ubuntu"
|
||
OS_VERSION="22.04"
|
||
OS_CODENAME="jammy"
|
||
OS_DISPLAY="Ubuntu 22.04 LTS"
|
||
;;
|
||
esac
|
||
echo -e "${OS}${BOLD}${DGN}Operating System: ${BGN}${OS_DISPLAY}${CL}"
|
||
else
|
||
exit-script
|
||
fi
|
||
}
|
||
|
||
function select_cloud_init() {
|
||
# Ubuntu only has cloudimg variant (always Cloud-Init), so no choice needed
|
||
if [ "$OS_TYPE" = "ubuntu" ]; then
|
||
USE_CLOUD_INIT="yes"
|
||
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}yes (Ubuntu requires Cloud-Init)${CL}"
|
||
return
|
||
fi
|
||
|
||
# Debian has two image variants, so user can choose
|
||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "CLOUD-INIT" \
|
||
--yesno "Enable Cloud-Init for VM configuration?\n\nCloud-Init allows automatic configuration of:\n- User accounts and passwords\n- SSH keys\n- Network settings (DHCP/Static)\n- DNS configuration\n\nYou can also configure these settings later in Proxmox UI.\n\nNote: Debian without Cloud-Init will use nocloud image with console auto-login." 18 68); then
|
||
USE_CLOUD_INIT="yes"
|
||
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}yes${CL}"
|
||
else
|
||
USE_CLOUD_INIT="no"
|
||
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}no${CL}"
|
||
fi
|
||
}
|
||
|
||
function select_portainer() {
|
||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "PORTAINER" \
|
||
--yesno "Install Portainer for Docker management?\n\nPortainer is a lightweight management UI for Docker.\n\nAccess after installation:\n- HTTP: http://<VM-IP>:9000\n- HTTPS: https://<VM-IP>:9443" 14 68); then
|
||
INSTALL_PORTAINER="yes"
|
||
echo -e "${ADVANCED}${BOLD}${DGN}Portainer: ${BGN}yes${CL}"
|
||
else
|
||
INSTALL_PORTAINER="no"
|
||
echo -e "${ADVANCED}${BOLD}${DGN}Portainer: ${BGN}no${CL}"
|
||
fi
|
||
}
|
||
|
||
function get_image_url() {
|
||
local arch=$(dpkg --print-architecture)
|
||
case $OS_TYPE in
|
||
debian)
|
||
# Debian has two variants:
|
||
# - generic: For Cloud-Init enabled VMs
|
||
# - nocloud: For VMs without Cloud-Init (has console auto-login)
|
||
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||
echo "https://cloud.debian.org/images/cloud/${OS_CODENAME}/latest/debian-${OS_VERSION}-generic-${arch}.qcow2"
|
||
else
|
||
echo "https://cloud.debian.org/images/cloud/${OS_CODENAME}/latest/debian-${OS_VERSION}-nocloud-${arch}.qcow2"
|
||
fi
|
||
;;
|
||
ubuntu)
|
||
# Ubuntu only has cloudimg variant (always with Cloud-Init support)
|
||
echo "https://cloud-images.ubuntu.com/${OS_CODENAME}/current/${OS_CODENAME}-server-cloudimg-${arch}.img"
|
||
;;
|
||
esac
|
||
}
|
||
|
||
function default_settings() {
|
||
# OS Selection - ALWAYS ask
|
||
select_os
|
||
|
||
# Cloud-Init Selection - ALWAYS ask
|
||
select_cloud_init
|
||
|
||
# Portainer Selection - ALWAYS ask
|
||
select_portainer
|
||
|
||
# Set defaults for other settings
|
||
VMID=$(get_valid_nextid)
|
||
FORMAT=""
|
||
MACHINE=" -machine q35"
|
||
DISK_CACHE=""
|
||
DISK_SIZE="10G"
|
||
HN="docker"
|
||
CPU_TYPE=" -cpu host"
|
||
CORE_COUNT="2"
|
||
RAM_SIZE="4096"
|
||
BRG="vmbr0"
|
||
MAC="$GEN_MAC"
|
||
VLAN=""
|
||
MTU=""
|
||
START_VM="yes"
|
||
METHOD="default"
|
||
|
||
# Display summary
|
||
echo -e "${CONTAINERID}${BOLD}${DGN}Virtual Machine ID: ${BGN}${VMID}${CL}"
|
||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}Q35 (Modern)${CL}"
|
||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Size: ${BGN}${DISK_SIZE}${CL}"
|
||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
|
||
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}${HN}${CL}"
|
||
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
|
||
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}${CORE_COUNT}${CL}"
|
||
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}${RAM_SIZE}${CL}"
|
||
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}${BRG}${CL}"
|
||
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}${MAC}${CL}"
|
||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}Default${CL}"
|
||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}Default${CL}"
|
||
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||
echo -e "${CREATING}${BOLD}${DGN}Creating a Docker VM using the above settings${CL}"
|
||
}
|
||
|
||
function advanced_settings() {
|
||
# OS Selection - ALWAYS ask (at the beginning)
|
||
select_os
|
||
|
||
# Cloud-Init Selection - ALWAYS ask (at the beginning)
|
||
select_cloud_init
|
||
|
||
# Portainer Selection - ALWAYS ask (at the beginning)
|
||
select_portainer
|
||
|
||
METHOD="advanced"
|
||
[ -z "${VMID:-}" ] && VMID=$(get_valid_nextid)
|
||
while true; do
|
||
if VMID=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Virtual Machine ID" 8 58 $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
|
||
|
||
if MACH=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "MACHINE TYPE" --radiolist --cancel-button Exit-Script "Choose Type" 10 58 2 \
|
||
"q35" "Q35 (Modern, PCIe)" ON \
|
||
"i440fx" "i440fx (Legacy, PCI)" OFF \
|
||
3>&1 1>&2 2>&3); then
|
||
if [ $MACH = q35 ]; then
|
||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}Q35 (Modern)${CL}"
|
||
FORMAT=""
|
||
MACHINE=" -machine q35"
|
||
else
|
||
echo -e "${CONTAINERTYPE}${BOLD}${DGN}Machine Type: ${BGN}i440fx (Legacy)${CL}"
|
||
FORMAT=",efitype=4m"
|
||
MACHINE=""
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if DISK_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Disk Size in GiB (e.g., 10, 20)" 8 58 "$DISK_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
|
||
|
||
if DISK_CACHE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "DISK CACHE" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||
"0" "None (Default)" ON \
|
||
"1" "Write Through" OFF \
|
||
3>&1 1>&2 2>&3); then
|
||
if [ $DISK_CACHE = "1" ]; then
|
||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}Write Through${CL}"
|
||
DISK_CACHE="cache=writethrough,"
|
||
else
|
||
echo -e "${DISKSIZE}${BOLD}${DGN}Disk Cache: ${BGN}None${CL}"
|
||
DISK_CACHE=""
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if VM_NAME=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Hostname" 8 58 docker --title "HOSTNAME" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||
if [ -z $VM_NAME ]; then
|
||
HN="docker"
|
||
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
|
||
else
|
||
HN=$(echo ${VM_NAME,,} | tr -d ' ')
|
||
echo -e "${HOSTNAME}${BOLD}${DGN}Hostname: ${BGN}$HN${CL}"
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if CPU_TYPE1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --title "CPU MODEL" --radiolist "Choose" --cancel-button Exit-Script 10 58 2 \
|
||
"1" "Host (Recommended)" ON \
|
||
"0" "KVM64" OFF \
|
||
3>&1 1>&2 2>&3); then
|
||
if [ $CPU_TYPE1 = "1" ]; then
|
||
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}Host${CL}"
|
||
CPU_TYPE=" -cpu host"
|
||
else
|
||
echo -e "${OS}${BOLD}${DGN}CPU Model: ${BGN}KVM64${CL}"
|
||
CPU_TYPE=""
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if CORE_COUNT=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate CPU Cores" 8 58 2 --title "CORE COUNT" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||
if [ -z $CORE_COUNT ]; then
|
||
CORE_COUNT="2"
|
||
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
|
||
else
|
||
echo -e "${CPUCORE}${BOLD}${DGN}CPU Cores: ${BGN}$CORE_COUNT${CL}"
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if RAM_SIZE=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Allocate RAM in MiB" 8 58 2048 --title "RAM" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||
if [ -z $RAM_SIZE ]; then
|
||
RAM_SIZE="2048"
|
||
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
|
||
else
|
||
echo -e "${RAMSIZE}${BOLD}${DGN}RAM Size: ${BGN}$RAM_SIZE${CL}"
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if BRG=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Bridge" 8 58 vmbr0 --title "BRIDGE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||
if [ -z $BRG ]; then
|
||
BRG="vmbr0"
|
||
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
|
||
else
|
||
echo -e "${BRIDGE}${BOLD}${DGN}Bridge: ${BGN}$BRG${CL}"
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if MAC1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a MAC Address" 8 58 $GEN_MAC --title "MAC ADDRESS" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||
if [ -z $MAC1 ]; then
|
||
MAC="$GEN_MAC"
|
||
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC${CL}"
|
||
else
|
||
MAC="$MAC1"
|
||
echo -e "${MACADDRESS}${BOLD}${DGN}MAC Address: ${BGN}$MAC1${CL}"
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if VLAN1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set a Vlan(leave blank for default)" 8 58 --title "VLAN" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||
if [ -z $VLAN1 ]; then
|
||
VLAN1="Default"
|
||
VLAN=""
|
||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
|
||
else
|
||
VLAN=",tag=$VLAN1"
|
||
echo -e "${VLANTAG}${BOLD}${DGN}VLAN: ${BGN}$VLAN1${CL}"
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if MTU1=$(whiptail --backtitle "Proxmox VE Helper Scripts" --inputbox "Set Interface MTU Size (leave blank for default)" 8 58 --title "MTU SIZE" --cancel-button Exit-Script 3>&1 1>&2 2>&3); then
|
||
if [ -z $MTU1 ]; then
|
||
MTU1="Default"
|
||
MTU=""
|
||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
|
||
else
|
||
MTU=",mtu=$MTU1"
|
||
echo -e "${DEFAULT}${BOLD}${DGN}Interface MTU Size: ${BGN}$MTU1${CL}"
|
||
fi
|
||
else
|
||
exit-script
|
||
fi
|
||
|
||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "START VIRTUAL MACHINE" --yesno "Start VM when completed?" 10 58); then
|
||
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}yes${CL}"
|
||
START_VM="yes"
|
||
else
|
||
echo -e "${GATEWAY}${BOLD}${DGN}Start VM when completed: ${BGN}no${CL}"
|
||
START_VM="no"
|
||
fi
|
||
|
||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "ADVANCED SETTINGS COMPLETE" --yesno "Ready to create a Docker VM?" --no-button Do-Over 10 58); then
|
||
echo -e "${CREATING}${BOLD}${DGN}Creating a Docker VM using the above advanced settings${CL}"
|
||
else
|
||
header_info
|
||
echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
|
||
advanced_settings
|
||
fi
|
||
}
|
||
|
||
function start_script() {
|
||
if (whiptail --backtitle "Proxmox VE Helper Scripts" --title "SETTINGS" --yesno "Use Default Settings?" --no-button Advanced 10 58); then
|
||
header_info
|
||
echo -e "${DEFAULT}${BOLD}${BL}Using Default Settings${CL}"
|
||
default_settings
|
||
else
|
||
header_info
|
||
echo -e "${ADVANCED}${BOLD}${RD}Using Advanced Settings${CL}"
|
||
advanced_settings
|
||
fi
|
||
}
|
||
check_root
|
||
arch_check
|
||
pve_check
|
||
ssh_check
|
||
start_script
|
||
post_to_api_vm
|
||
|
||
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 "
|
||
OFFSET=2
|
||
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=$(pvesm status -content images | awk 'NR>1')
|
||
if [ -z "$VALID" ]; then
|
||
msg_error "Unable to detect a valid storage location."
|
||
exit
|
||
elif [ $((${#STORAGE_MENU[@]} / 3)) -eq 1 ]; then
|
||
STORAGE=${STORAGE_MENU[0]}
|
||
else
|
||
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 ${HN}?\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}."
|
||
|
||
if ! command -v virt-customize &>/dev/null; then
|
||
msg_info "Installing Pre-Requisite libguestfs-tools onto Host"
|
||
apt-get -qq update >/dev/null
|
||
apt-get -qq install libguestfs-tools lsb-release -y >/dev/null
|
||
# Workaround for Proxmox VE 9.0 libguestfs issue
|
||
apt-get -qq install dhcpcd-base -y >/dev/null 2>&1 || true
|
||
msg_ok "Installed libguestfs-tools successfully"
|
||
fi
|
||
|
||
msg_info "Retrieving the URL for the ${OS_DISPLAY} Qcow2 Disk Image"
|
||
URL=$(get_image_url)
|
||
sleep 2
|
||
msg_ok "${CL}${BL}${URL}${CL}"
|
||
curl -f#SL -o "$(basename "$URL")" "$URL"
|
||
echo -en "\e[1A\e[0K"
|
||
FILE=$(basename $URL)
|
||
msg_ok "Downloaded ${CL}${BL}${FILE}${CL}"
|
||
|
||
STORAGE_TYPE=$(pvesm status -storage "$STORAGE" | awk 'NR>1 {print $2}')
|
||
case $STORAGE_TYPE in
|
||
nfs | dir)
|
||
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=""
|
||
;;
|
||
esac
|
||
for i in {0,1}; do
|
||
disk="DISK$i"
|
||
eval DISK${i}=vm-${VMID}-disk-${i}${DISK_EXT:-}
|
||
eval DISK${i}_REF=${STORAGE}:${DISK_REF:-}${!disk}
|
||
done
|
||
|
||
echo -e "${INFO}${BOLD}${GN}Preparing ${OS_DISPLAY} Qcow2 Disk Image${CL}"
|
||
|
||
# Set DNS for libguestfs appliance environment (not the guest)
|
||
export LIBGUESTFS_BACKEND_SETTINGS=dns=8.8.8.8,1.1.1.1
|
||
|
||
# Create install-docker.sh with Portainer support if requested
|
||
if [ "$INSTALL_PORTAINER" = "yes" ]; then
|
||
virt-customize -q -a "${FILE}" --run-command "cat > /root/install-docker.sh << \"INSTALLEOF\"
|
||
#!/bin/bash
|
||
# Log output to file
|
||
exec > /var/log/install-docker.log 2>&1
|
||
echo \"[\\$(date)] Starting Docker installation on first boot\"
|
||
|
||
# Check if Docker is already installed
|
||
if command -v docker >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Docker already installed, checking if running\"
|
||
systemctl start docker 2>/dev/null || true
|
||
if docker info >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Docker is already working, exiting\"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
# Wait for network to be fully available
|
||
for i in {1..30}; do
|
||
if ping -c 1 8.8.8.8 >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Network is available\"
|
||
break
|
||
fi
|
||
echo \"[\\$(date)] Waiting for network... attempt \\\$i/30\"
|
||
sleep 2
|
||
done
|
||
|
||
# Configure DNS
|
||
echo \"[\\$(date)] Configuring DNS\"
|
||
mkdir -p /etc/systemd/resolved.conf.d
|
||
cat > /etc/systemd/resolved.conf.d/dns.conf << DNSEOF
|
||
[Resolve]
|
||
DNS=8.8.8.8 1.1.1.1
|
||
FallbackDNS=8.8.4.4 1.0.0.1
|
||
DNSEOF
|
||
systemctl restart systemd-resolved 2>/dev/null || true
|
||
|
||
# Update package lists
|
||
echo \"[\\$(date)] Updating package lists\"
|
||
apt-get update
|
||
|
||
# Install base packages if not already installed
|
||
echo \"[\\$(date)] Installing base packages\"
|
||
apt-get install -y qemu-guest-agent curl ca-certificates 2>/dev/null || true
|
||
|
||
# Install Docker
|
||
echo \"[\\$(date)] Installing Docker\"
|
||
curl -fsSL https://get.docker.com | sh
|
||
systemctl enable docker
|
||
systemctl start docker
|
||
|
||
# Wait for Docker to be ready
|
||
for i in {1..10}; do
|
||
if docker info >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Docker is ready\"
|
||
break
|
||
fi
|
||
sleep 1
|
||
done
|
||
|
||
# Install Portainer
|
||
/root/portainer-install.sh
|
||
|
||
# Create completion flag
|
||
echo \"[\\$(date)] Docker installation completed successfully\"
|
||
touch /root/.docker-installed
|
||
INSTALLEOF" >/dev/null
|
||
else
|
||
virt-customize -q -a "${FILE}" --run-command "cat > /root/install-docker.sh << \"INSTALLEOF\"
|
||
#!/bin/bash
|
||
# Log output to file
|
||
exec > /var/log/install-docker.log 2>&1
|
||
echo \"[\\$(date)] Starting Docker installation on first boot\"
|
||
|
||
# Check if Docker is already installed
|
||
if command -v docker >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Docker already installed, checking if running\"
|
||
systemctl start docker 2>/dev/null || true
|
||
if docker info >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Docker is already working, exiting\"
|
||
exit 0
|
||
fi
|
||
fi
|
||
|
||
# Wait for network to be fully available
|
||
for i in {1..30}; do
|
||
if ping -c 1 8.8.8.8 >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Network is available\"
|
||
break
|
||
fi
|
||
echo \"[\\$(date)] Waiting for network... attempt \\\$i/30\"
|
||
sleep 2
|
||
done
|
||
|
||
# Configure DNS
|
||
echo \"[\\$(date)] Configuring DNS\"
|
||
mkdir -p /etc/systemd/resolved.conf.d
|
||
cat > /etc/systemd/resolved.conf.d/dns.conf << DNSEOF
|
||
[Resolve]
|
||
DNS=8.8.8.8 1.1.1.1
|
||
FallbackDNS=8.8.4.4 1.0.0.1
|
||
DNSEOF
|
||
systemctl restart systemd-resolved 2>/dev/null || true
|
||
|
||
# Update package lists
|
||
echo \"[\\$(date)] Updating package lists\"
|
||
apt-get update
|
||
|
||
# Install base packages if not already installed
|
||
echo \"[\\$(date)] Installing base packages\"
|
||
apt-get install -y qemu-guest-agent curl ca-certificates 2>/dev/null || true
|
||
|
||
# Install Docker
|
||
echo \"[\\$(date)] Installing Docker\"
|
||
curl -fsSL https://get.docker.com | sh
|
||
systemctl enable docker
|
||
systemctl start docker
|
||
|
||
# Wait for Docker to be ready
|
||
for i in {1..10}; do
|
||
if docker info >/dev/null 2>&1; then
|
||
echo \"[\\$(date)] Docker is ready\"
|
||
break
|
||
fi
|
||
sleep 1
|
||
done
|
||
|
||
# Portainer not requested - skip installation
|
||
|
||
# Create completion flag
|
||
echo \"[\\$(date)] Docker installation completed successfully\"
|
||
touch /root/.docker-installed
|
||
INSTALLEOF" >/dev/null
|
||
fi
|
||
|
||
# Add Portainer installation script if requested
|
||
if [ "$INSTALL_PORTAINER" = "yes" ]; then
|
||
virt-customize -q -a "${FILE}" --run-command 'cat > /root/portainer-install.sh << '"'"'PORTAINEREOF'"'"'
|
||
#!/bin/bash
|
||
exec >> /var/log/install-docker.log 2>&1
|
||
echo "[$(date)] Installing Portainer"
|
||
docker volume create portainer_data 2>/dev/null || true
|
||
docker run -d \
|
||
-p 9000:9000 \
|
||
-p 9443:9443 \
|
||
--name=portainer \
|
||
--restart=always \
|
||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||
-v portainer_data:/data \
|
||
portainer/portainer-ce:latest
|
||
echo "[$(date)] Portainer installed"
|
||
PORTAINEREOF' >/dev/null
|
||
|
||
virt-customize -q -a "${FILE}" --run-command 'chmod +x /root/portainer-install.sh' >/dev/null
|
||
fi
|
||
|
||
virt-customize -q -a "${FILE}" --run-command "chmod +x /root/install-docker.sh" >/dev/null
|
||
|
||
virt-customize -q -a "${FILE}" --run-command 'cat > /etc/systemd/system/install-docker.service << "SERVICEEOF"
|
||
[Unit]
|
||
Description=Install Docker on First Boot
|
||
After=network-online.target
|
||
Wants=network-online.target
|
||
ConditionPathExists=!/root/.docker-installed
|
||
|
||
[Service]
|
||
Type=oneshot
|
||
ExecStart=/root/install-docker.sh
|
||
RemainAfterExit=yes
|
||
|
||
[Install]
|
||
WantedBy=multi-user.target
|
||
SERVICEEOF
|
||
' >/dev/null
|
||
|
||
virt-customize -q -a "${FILE}" --run-command "systemctl enable install-docker.service" >/dev/null
|
||
|
||
# Try to install packages and Docker during image customization
|
||
DOCKER_INSTALLED_ON_FIRST_BOOT="yes" # Assume first-boot by default
|
||
|
||
msg_info "Installing base packages (qemu-guest-agent, curl, ca-certificates)"
|
||
if virt-customize -a "${FILE}" --install qemu-guest-agent,curl,ca-certificates >/dev/null 2>&1; then
|
||
msg_ok "Installed base packages"
|
||
|
||
msg_info "Installing Docker via get.docker.com"
|
||
if virt-customize -q -a "${FILE}" --run-command "curl -fsSL https://get.docker.com | sh" >/dev/null 2>&1 &&
|
||
virt-customize -q -a "${FILE}" --run-command "systemctl enable docker" >/dev/null 2>&1; then
|
||
msg_ok "Installed Docker"
|
||
|
||
# Optimize Docker daemon configuration
|
||
virt-customize -q -a "${FILE}" --run-command "mkdir -p /etc/docker" >/dev/null 2>&1
|
||
virt-customize -q -a "${FILE}" --run-command "cat > /etc/docker/daemon.json << 'DOCKEREOF'
|
||
{
|
||
\"storage-driver\": \"overlay2\",
|
||
\"log-driver\": \"json-file\",
|
||
\"log-opts\": {
|
||
\"max-size\": \"10m\",
|
||
\"max-file\": \"3\"
|
||
}
|
||
}
|
||
DOCKEREOF" >/dev/null 2>&1
|
||
|
||
# Create completion flag to prevent first-boot script from running
|
||
virt-customize -q -a "${FILE}" --run-command "touch /root/.docker-installed" >/dev/null 2>&1
|
||
|
||
DOCKER_INSTALLED_ON_FIRST_BOOT="no"
|
||
else
|
||
msg_ok "Docker will be installed on first boot (installation failed during image preparation)"
|
||
fi
|
||
else
|
||
msg_ok "Packages will be installed on first boot (network not available during image preparation)"
|
||
fi
|
||
|
||
# Set hostname and clean machine-id
|
||
virt-customize -q -a "${FILE}" --hostname "${HN}" >/dev/null 2>&1
|
||
virt-customize -q -a "${FILE}" --run-command "truncate -s 0 /etc/machine-id" >/dev/null 2>&1
|
||
virt-customize -q -a "${FILE}" --run-command "rm -f /var/lib/dbus/machine-id" >/dev/null 2>&1
|
||
|
||
# Configure SSH to allow root login with password when Cloud-Init is enabled
|
||
# (Cloud-Init will set the password, but SSH needs to accept password authentication)
|
||
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||
virt-customize -q -a "${FILE}" --run-command "sed -i 's/^#*PermitRootLogin.*/PermitRootLogin yes/' /etc/ssh/sshd_config" >/dev/null 2>&1 || true
|
||
virt-customize -q -a "${FILE}" --run-command "sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication yes/' /etc/ssh/sshd_config" >/dev/null 2>&1 || true
|
||
fi
|
||
|
||
msg_info "Expanding root partition to use full disk space"
|
||
qemu-img create -f qcow2 expanded.qcow2 ${DISK_SIZE} >/dev/null 2>&1
|
||
virt-resize --quiet --expand /dev/sda1 ${FILE} expanded.qcow2 >/dev/null 2>&1
|
||
mv expanded.qcow2 ${FILE} >/dev/null 2>&1
|
||
msg_ok "Expanded image to full size"
|
||
|
||
msg_info "Creating a Docker VM"
|
||
|
||
qm create $VMID -agent 1${MACHINE} -tablet 0 -localtime 1 -bios ovmf${CPU_TYPE} -cores $CORE_COUNT -memory $RAM_SIZE \
|
||
-name $HN -tags community-script -net0 virtio,bridge=$BRG,macaddr=$MAC$VLAN$MTU -onboot 1 -ostype l26 -scsihw virtio-scsi-pci
|
||
pvesm alloc $STORAGE $VMID $DISK0 4M 1>&/dev/null
|
||
qm importdisk $VMID ${FILE} $STORAGE ${DISK_IMPORT:-} 1>&/dev/null
|
||
qm set $VMID \
|
||
-efidisk0 ${DISK0_REF}${FORMAT} \
|
||
-scsi0 ${DISK1_REF},${DISK_CACHE}${THIN}size=${DISK_SIZE} \
|
||
-boot order=scsi0 \
|
||
-serial0 socket >/dev/null
|
||
qm set $VMID --agent enabled=1 >/dev/null
|
||
|
||
# Proxmox 9: Enable I/O Thread for better disk performance
|
||
if [ "${PVE_MAJOR:-8}" = "9" ]; then
|
||
qm set $VMID -iothread 1 >/dev/null 2>&1 || true
|
||
fi
|
||
|
||
msg_ok "Created a Docker VM ${CL}${BL}(${HN})${CL}"
|
||
|
||
# Add Cloud-Init drive if requested
|
||
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||
msg_info "Configuring Cloud-Init"
|
||
setup_cloud_init "$VMID" "$STORAGE" "$HN" "yes" >/dev/null 2>&1
|
||
msg_ok "Cloud-Init configured"
|
||
fi
|
||
|
||
DESCRIPTION=$(
|
||
cat <<EOF
|
||
<div align='center'>
|
||
<a href='https://Helper-Scripts.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;'>Docker VM</h2>
|
||
|
||
<p style='margin: 16px 0;'>
|
||
<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>
|
||
|
||
<span style='margin: 0 10px;'>
|
||
<i class="fa fa-github fa-fw" style="color: #f5f5f5;"></i>
|
||
<a href='https://github.com/community-scripts/ProxmoxVE' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>GitHub</a>
|
||
</span>
|
||
<span style='margin: 0 10px;'>
|
||
<i class="fa fa-comments fa-fw" style="color: #f5f5f5;"></i>
|
||
<a href='https://github.com/community-scripts/ProxmoxVE/discussions' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Discussions</a>
|
||
</span>
|
||
<span style='margin: 0 10px;'>
|
||
<i class="fa fa-exclamation-circle fa-fw" style="color: #f5f5f5;"></i>
|
||
<a href='https://github.com/community-scripts/ProxmoxVE/issues' target='_blank' rel='noopener noreferrer' style='text-decoration: none; color: #00617f;'>Issues</a>
|
||
</span>
|
||
</div>
|
||
EOF
|
||
)
|
||
qm set "$VMID" -description "$DESCRIPTION" >/dev/null
|
||
|
||
if [ "$START_VM" == "yes" ]; then
|
||
msg_info "Starting Docker VM"
|
||
qm start $VMID >/dev/null 2>&1
|
||
msg_ok "Started Docker VM"
|
||
fi
|
||
|
||
# Try to get VM IP address silently in background (max 10 seconds)
|
||
VM_IP=""
|
||
if [ "$START_VM" == "yes" ]; then
|
||
for i in {1..5}; do
|
||
VM_IP=$(qm guest cmd "$VMID" network-get-interfaces 2>/dev/null |
|
||
jq -r '.[] | select(.name != "lo") | ."ip-addresses"[]? | select(."ip-address-type" == "ipv4") | ."ip-address"' 2>/dev/null |
|
||
grep -v "^127\." | head -1)
|
||
|
||
if [ -n "$VM_IP" ]; then
|
||
break
|
||
fi
|
||
sleep 2
|
||
done
|
||
fi
|
||
|
||
# Display information about installed components
|
||
echo -e "\n${INFO}${BOLD}${GN}VM Configuration Summary:${CL}"
|
||
echo -e "${TAB}${DGN}VM ID: ${BGN}${VMID}${CL}"
|
||
echo -e "${TAB}${DGN}Hostname: ${BGN}${HN}${CL}"
|
||
echo -e "${TAB}${DGN}OS: ${BGN}${OS_DISPLAY}${CL}"
|
||
|
||
if [ -n "$VM_IP" ]; then
|
||
echo -e "${TAB}${DGN}IP Address: ${BGN}${VM_IP}${CL}"
|
||
fi
|
||
|
||
if [ "$DOCKER_INSTALLED_ON_FIRST_BOOT" = "yes" ]; then
|
||
echo -e "${TAB}${DGN}Docker: ${BGN}Will be installed on first boot${CL}"
|
||
echo -e "${TAB}${YW}⚠️ Docker installation will happen automatically after VM starts${CL}"
|
||
echo -e "${TAB}${YW}⚠️ Wait 2-3 minutes after boot for installation to complete${CL}"
|
||
echo -e "${TAB}${YW}⚠️ Check installation progress: ${BL}cat /var/log/install-docker.log${CL}"
|
||
else
|
||
echo -e "${TAB}${DGN}Docker: ${BGN}Latest (via get.docker.com)${CL}"
|
||
fi
|
||
|
||
if [ "$INSTALL_PORTAINER" = "yes" ]; then
|
||
if [ -n "$VM_IP" ]; then
|
||
echo -e "${TAB}${DGN}Portainer: ${BGN}https://${VM_IP}:9443${CL}"
|
||
else
|
||
echo -e "${TAB}${DGN}Portainer: ${BGN}Will be accessible at https://<VM-IP>:9443${CL}"
|
||
echo -e "${TAB}${YW}⚠️ Wait 2-3 minutes after boot for installation to complete${CL}"
|
||
echo -e "${TAB}${YW}⚠️ Get IP with: ${BL}qm guest cmd ${VMID} network-get-interfaces${CL}"
|
||
fi
|
||
fi
|
||
if [ "$USE_CLOUD_INIT" = "yes" ]; then
|
||
display_cloud_init_info "$VMID" "$HN"
|
||
fi
|
||
|
||
post_update_to_api "done" "none"
|
||
msg_ok "Completed Successfully!\n"
|