Automate VM provisioning via serial console

Replaces SSH-based installation with serial console automation using a new send_line_to_vm function. The script now logs in, installs Podman, downloads and installs UniFi OS Server, and retrieves the VM IP address directly via the console. This simplifies the process and removes SSH and sshpass dependencies.
This commit is contained in:
CanbiZ 2026-01-07 17:23:36 +01:00
parent a0f54d8bf6
commit 2c348d4d94

View File

@ -107,6 +107,77 @@ function cleanup_vmid() {
fi
}
function send_line_to_vm() {
local line="$1"
echo -e "${DGN}Sending: ${YW}${line}${CL}"
for ((i = 0; i < ${#line}; i++)); do
character=${line:i:1}
case $character in
" ") character="spc" ;;
"-") character="minus" ;;
"=") character="equal" ;;
",") character="comma" ;;
".") character="dot" ;;
"/") character="slash" ;;
"'") character="apostrophe" ;;
";") character="semicolon" ;;
'\') character="backslash" ;;
'\`') character="grave_accent" ;;
"[") character="bracket_left" ;;
"]") character="bracket_right" ;;
"_") character="shift-minus" ;;
"+") character="shift-equal" ;;
"?") character="shift-slash" ;;
"<") character="shift-comma" ;;
">") character="shift-dot" ;;
'"') character="shift-apostrophe" ;;
":") character="shift-semicolon" ;;
"|") character="shift-backslash" ;;
"~") character="shift-grave_accent" ;;
"{") character="shift-bracket_left" ;;
"}") character="shift-bracket_right" ;;
"A") character="shift-a" ;;
"B") character="shift-b" ;;
"C") character="shift-c" ;;
"D") character="shift-d" ;;
"E") character="shift-e" ;;
"F") character="shift-f" ;;
"G") character="shift-g" ;;
"H") character="shift-h" ;;
"I") character="shift-i" ;;
"J") character="shift-j" ;;
"K") character="shift-k" ;;
"L") character="shift-l" ;;
"M") character="shift-m" ;;
"N") character="shift-n" ;;
"O") character="shift-o" ;;
"P") character="shift-p" ;;
"Q") character="shift-q" ;;
"R") character="shift-r" ;;
"S") character="shift-s" ;;
"T") character="shift-t" ;;
"U") character="shift-u" ;;
"V") character="shift-v" ;;
"W") character="shift-w" ;;
"X") character="shift-x" ;;
"Y") character="shift-y" ;;
"Z") character="shift-z" ;;
"!") character="shift-1" ;;
"@") character="shift-2" ;;
"#") character="shift-3" ;;
'$') character="shift-4" ;;
"%") character="shift-5" ;;
"^") character="shift-6" ;;
"&") character="shift-7" ;;
"*") character="shift-8" ;;
"(") character="shift-9" ;;
")") character="shift-0" ;;
esac
qm sendkey $VMID "$character"
done
qm sendkey $VMID ret
}
function cleanup() {
popd >/dev/null
post_update_to_api "done" "none"
@ -229,7 +300,7 @@ function select_os() {
OS_DISPLAY="Ubuntu 24.04 LTS"
;;
esac
echo -e "${OS}${BOLD}${DGN}Operating System: ${BGN}${OS_DISPLAY}${CL}"
#echo -e "${OS}${BOLD}${DGN}Operating System: ${BGN}${OS_DISPLAY}${CL}"
else
exit-script
fi
@ -238,14 +309,14 @@ function select_os() {
function select_cloud_init() {
# UniFi OS Server ALWAYS requires Cloud-Init for automated installation
USE_CLOUD_INIT="yes"
echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}yes (required for UniFi OS)${CL}"
#echo -e "${CLOUD}${BOLD}${DGN}Cloud-Init: ${BGN}yes (required for UniFi OS)${CL}"
}
function get_image_url() {
local arch=$(dpkg --print-architecture)
case $OS_TYPE in
debian)
# Always use generic (Cloud-Init) variant for UniFi OS
# Always use <ic (Cloud-Init) variant for UniFi OS
echo "https://cloud.debian.org/images/cloud/${OS_CODENAME}/latest/debian-${OS_VERSION}-generic-${arch}.qcow2"
;;
ubuntu)
@ -679,138 +750,72 @@ if [ "$START_VM" == "yes" ]; then
qm start $VMID
msg_ok "Started UniFi OS VM"
msg_info "Waiting for VM to boot and Cloud-Init to complete (60-90 seconds)"
sleep 60
msg_info "Waiting for VM to boot and Cloud-Init to complete (this takes ~90 seconds)"
sleep 90
msg_ok "VM boot complete"
# Login via serial console
msg_info "Logging into VM via serial console"
send_line_to_vm "root"
sleep 2
send_line_to_vm "${CLOUDINIT_PASSWORD}"
sleep 3
msg_ok "Logged into VM"
# Step 1: Update and install Podman
msg_info "Installing Podman and dependencies (this takes 2-3 minutes)"
send_line_to_vm "export DEBIAN_FRONTEND=noninteractive"
sleep 1
send_line_to_vm "apt-get update -qq"
sleep 30
send_line_to_vm "apt-get install -y podman uidmap slirp4netns curl wget -qq"
sleep 120
msg_ok "Podman installed"
# Step 2: Download UniFi OS Server installer
msg_info "Downloading UniFi OS Server ${UOS_VERSION}"
send_line_to_vm "cd /opt"
sleep 1
send_line_to_vm "wget -q ${UOS_URL} -O unifi-os-server.bin"
sleep 60
send_line_to_vm "chmod +x unifi-os-server.bin"
sleep 2
msg_ok "Downloaded UniFi OS Server installer"
# Step 3: Install UniFi OS Server (with auto-yes)
msg_info "Installing UniFi OS Server (this takes 3-5 minutes)"
send_line_to_vm "echo y | ./unifi-os-server.bin"
sleep 300
msg_ok "UniFi OS Server installed"
# Step 4: Get IP address for final message
msg_info "Detecting VM IP address"
sleep 5
VM_IP=""
for i in {1..30}; do
VM_IP=$(qm guest cmd $VMID network-get-interfaces 2>/dev/null | jq -r '.[1]["ip-addresses"][]? | select(.["ip-address-type"] == "ipv4") | .["ip-address"]' 2>/dev/null | grep -v "127.0.0.1" | head -1 || echo "")
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 | head -1 || echo "")
if [ -n "$VM_IP" ]; then
break
fi
sleep 2
done
if [ -n "$VM_IP" ]; then
msg_ok "VM IP Address: ${VM_IP}"
break
fi
sleep 2
done
if [ -z "$VM_IP" ]; then
msg_error "Could not detect VM IP address"
echo -e "${TAB}${INFO}${YW}Use Proxmox Console to login with Cloud-Init credentials${CL}"
echo -e "${TAB}${INFO}${YW}User: ${BGN}${CLOUDINIT_USER:-root}${CL} / Password: ${BGN}${CLOUDINIT_PASSWORD}${CL}"
exit 1
fi
# Wait for SSH to be ready
msg_info "Waiting for SSH to be ready"
SSH_READY=0
for i in {1..30}; do
if timeout 5 sshpass -p "${CLOUDINIT_PASSWORD}" ssh -o ConnectTimeout=3 -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
"${CLOUDINIT_USER:-root}@${VM_IP}" "echo 'SSH Ready'" >/dev/null 2>&1; then
SSH_READY=1
msg_ok "SSH connection ready"
break
fi
sleep 2
done
if [ $SSH_READY -eq 0 ]; then
msg_error "SSH connection failed"
echo -e "${TAB}${INFO}${YW}Manual login - User: ${BGN}${CLOUDINIT_USER:-root}${CL} / Password: ${BGN}${CLOUDINIT_PASSWORD}${CL}"
exit 1
fi
# Check if sshpass is installed
if ! command -v sshpass &>/dev/null; then
msg_info "Installing sshpass for automated SSH"
apt-get update -qq >/dev/null 2>&1
apt-get install -y sshpass -qq >/dev/null 2>&1
fi
# Execute UniFi OS installation directly via SSH
msg_info "Installing UniFi OS Server ${UOS_VERSION} (takes 4-6 minutes)"
# Create installation script
INSTALL_SCRIPT=$(
cat <<'EOFINSTALL'
#!/bin/bash
set -e
export DEBIAN_FRONTEND=noninteractive
echo "[1/5] Updating system packages..."
apt-get update -qq
apt-get install -y curl wget ca-certificates podman uidmap slirp4netns iptables -qq
echo "[2/5] Configuring Podman..."
loginctl enable-linger root
echo "[3/5] Downloading UniFi OS Server installer..."
cd /root
curl -fsSL "UNIFI_URL" -o unifi-installer.bin
chmod +x unifi-installer.bin
echo "[4/5] Installing UniFi OS Server (this takes 3-5 minutes)..."
./unifi-installer.bin install
echo "[5/5] Starting UniFi OS Server..."
sleep 15
if systemctl list-unit-files | grep -q unifi-os-server; then
systemctl enable unifi-os-server
systemctl start unifi-os-server
sleep 10
if systemctl is-active --quiet unifi-os-server; then
echo "✓ UniFi OS Server is running"
else
echo "⚠ Service status:"
systemctl status unifi-os-server --no-pager || true
msg_info "IP address will be shown in VM console"
send_line_to_vm "ip -4 addr show | grep inet | grep -v 127.0.0.1"
fi
fi
echo "Installation completed!"
EOFINSTALL
)
# Replace URL placeholder
INSTALL_SCRIPT="${INSTALL_SCRIPT//UNIFI_URL/$UOS_URL}"
# Execute installation via SSH (with output streaming)
if sshpass -p "${CLOUDINIT_PASSWORD}" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
"${CLOUDINIT_USER:-root}@${VM_IP}" "bash -s" <<<"$INSTALL_SCRIPT" 2>&1 | while IFS= read -r line; do
echo -e "${TAB}${DGN}${line}${CL}"
done; then
msg_ok "UniFi OS Server installed successfully"
else
msg_error "Installation failed"
echo -e "${TAB}${INFO}${YW}Check logs: ${BL}ssh ${CLOUDINIT_USER:-root}@${VM_IP}${CL}"
exit 1
fi
# Wait for UniFi OS web interface
msg_info "Waiting for UniFi OS web interface (port 11443)"
PORT_OPEN=0
for i in {1..60}; do
if timeout 2 bash -c ">/dev/tcp/${VM_IP}/11443" 2>/dev/null; then
PORT_OPEN=1
msg_ok "UniFi OS Server web interface is ready"
break
fi
sleep 2
done
echo ""
if [ $PORT_OPEN -eq 1 ]; then
echo -e "${TAB}${GATEWAY}${BOLD}${GN}✓ UniFi OS Server is ready!${CL}"
echo -e "${TAB}${GATEWAY}${BOLD}${GN}✓ UniFi OS Server installation complete!${CL}"
if [ -n "$VM_IP" ]; then
echo -e "${TAB}${GATEWAY}${BOLD}${GN}✓ Access at: ${BGN}https://${VM_IP}:11443${CL}"
else
echo -e "${TAB}${INFO}${YW}UniFi OS is installed but web interface not yet available${CL}"
echo -e "${TAB}${INFO}${YW}Access at: ${BGN}https://${VM_IP}:11443${CL} ${YW}(may take 1-2 more minutes)${CL}"
echo -e "${TAB}${INFO}${YW}Access via: ${BGN}https://<VM-IP>:11443${CL}"
fi
echo -e "${TAB}${INFO}${DGN}SSH Access: ${BL}ssh ${CLOUDINIT_USER:-root}@${VM_IP}${CL}"
echo -e "${TAB}${INFO}${DGN}Password: ${BGN}${CLOUDINIT_PASSWORD}${CL}"
echo -e "${TAB}${INFO}${DGN}Console login - User: ${BGN}root${CL} / Password: ${BGN}${CLOUDINIT_PASSWORD}${CL}"
echo -e "${TAB}${INFO}${YW}Note: UniFi OS may take 1-2 more minutes to fully start${CL}"
echo ""
fi