#!/bin/bash source ~/.bashrc # Destroy Existing VMs and Recreate from Ubuntu Cloud-Init Template # This script creates a template from Ubuntu Cloud Image and recreates all VMs set -e # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' CYAN='\033[0;36m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_step() { echo -e "${BLUE}[STEP]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_header() { echo -e "${CYAN}========================================${NC}" echo -e "${CYAN}$1${NC}" echo -e "${CYAN}========================================${NC}" } # Load environment variables if [ -f .env ]; then set -a source <(grep -v '^#' .env | grep -v '^$' | sed 's/#.*$//' | sed 's/^[[:space:]]*//;s/[[:space:]]*$//' | grep '=') set +a fi PVE_USERNAME="${PVE_USERNAME:-root@pam}" PVE_PASSWORD="${PVE_ROOT_PASS:-}" PROXMOX_URL="https://192.168.1.206:8006" PROXMOX_NODE="pve" STORAGE="${STORAGE:-local-lvm}" TEMPLATE_ID=9000 TEMPLATE_NAME="ubuntu-24.04-cloudinit" # VM Configuration declare -A VMS=( [100]="cloudflare-tunnel:2:4096:40G:192.168.1.60:192.168.1.1" [101]="k3s-master:4:8192:80G:192.168.1.188:192.168.1.1" [102]="git-server:2:4096:100G:192.168.1.121:192.168.1.1" [103]="observability:4:8192:200G:192.168.1.82:192.168.1.1" ) # Get authentication ticket get_ticket() { local response=$(curl -k -s -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \ "$PROXMOX_URL/api2/json/access/ticket") local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4) local csrf=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4) if [ -z "$ticket" ] || [ -z "$csrf" ]; then log_error "Failed to authenticate with Proxmox" return 1 fi echo "$ticket|$csrf" } # Check if template exists template_exists() { local auth=$1 local ticket=$(echo "$auth" | cut -d'|' -f1) local csrf=$(echo "$auth" | cut -d'|' -f2) local response=$(curl -k -s \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_ID/config" 2>&1) if echo "$response" | grep -q '"name"'; then return 0 else return 1 fi } # Download Ubuntu Cloud Image download_cloud_image() { local image_url="https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img" local image_file="/tmp/ubuntu-24.04-server-cloudimg-amd64.img" log_step "Downloading Ubuntu 24.04 Cloud Image..." if [ -f "$image_file" ]; then log_info "Cloud image already exists: $image_file" return 0 fi log_info "Downloading from: $image_url" log_warn "This may take several minutes (image is ~2GB)..." if command -v wget &> /dev/null; then wget --progress=bar:force -O "$image_file" "$image_url" || return 1 elif command -v curl &> /dev/null; then curl -L --progress-bar -o "$image_file" "$image_url" || return 1 else log_error "Neither wget nor curl found" return 1 fi log_info "✓ Cloud image downloaded" echo "$image_file" } # Create template from cloud image create_template() { local auth=$1 local image_file=$2 local ticket=$(echo "$auth" | cut -d'|' -f1) local csrf=$(echo "$auth" | cut -d'|' -f2) log_step "Creating template from cloud image..." # Check if template already exists if template_exists "$auth"; then log_info "Template $TEMPLATE_ID already exists, skipping creation" return 0 fi log_warn "Template creation requires manual steps in Proxmox Web UI:" echo "" log_info "1. Upload cloud image to Proxmox:" log_info " - Go to: Datacenter → $PROXMOX_NODE → Storage → local" log_info " - Click 'Upload' → Select: $image_file" log_info " - Wait for upload to complete" echo "" log_info "2. Create VM from image:" log_info " - Create VM (ID: $TEMPLATE_ID)" log_info " - Import disk from uploaded image" log_info " - Set CPU: 2, Memory: 2048MB" log_info " - Add network device" log_info " - Enable Cloud-Init in Options" log_info " - Convert to template" echo "" log_warn "After template is created, press Enter to continue..." read -p "Press Enter when template is ready..." } # Destroy existing VM destroy_vm() { local auth=$1 local vmid=$2 local ticket=$(echo "$auth" | cut -d'|' -f1) local csrf=$(echo "$auth" | cut -d'|' -f2) log_step "Destroying VM $vmid..." # Stop VM if running curl -k -s -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null 2>&1 sleep 2 # Delete VM local response=$(curl -k -s -X DELETE \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid" 2>&1) if echo "$response" | grep -q '"errors"'; then log_error "Failed to destroy VM: $response" return 1 fi log_info "✓ VM $vmid destroyed" return 0 } # Create VM from template create_vm_from_template() { local auth=$1 local vmid=$2 local name=$3 local cores=$4 local memory=$5 local disk_size=$6 local ip_address=$7 local gateway=$8 local ticket=$(echo "$auth" | cut -d'|' -f1) local csrf=$(echo "$auth" | cut -d'|' -f2) log_step "Creating VM $vmid: $name from template..." # Clone template local clone_response=$(curl -k -s -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ -d "newid=$vmid" \ -d "name=$name" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_ID/clone" 2>&1) if echo "$clone_response" | grep -q '"errors"'; then log_error "Failed to clone template: $clone_response" return 1 fi log_info "Template cloned, waiting for completion..." sleep 5 # Configure VM log_info "Configuring VM..." # Set CPU, memory, disk curl -k -s -X PUT \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ -d "cores=$cores" \ -d "memory=$memory" \ -d "net0=virtio,bridge=vmbr0" \ -d "agent=1" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 # Resize disk if needed local current_disk=$(curl -k -s \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" | \ grep -o '"scsi0":"[^"]*' | cut -d'"' -f4 | cut -d',' -f2 | cut -d'=' -f2) if [ "$current_disk" != "$disk_size" ]; then log_info "Resizing disk to $disk_size..." curl -k -s -X PUT \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ -d "scsi0=${STORAGE}:${disk_size}" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/resize" > /dev/null 2>&1 fi # Configure Cloud-Init log_info "Configuring Cloud-Init..." curl -k -s -X PUT \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ -d "ipconfig0=ip=${ip_address}/24,gw=${gateway}" \ -d "ciuser=ubuntu" \ -d "cipassword=" \ -d "sshkeys=$(cat ~/.ssh/id_rsa.pub 2>/dev/null | base64 -w 0 || echo '')" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null 2>&1 log_info "✓ VM $vmid created and configured" return 0 } main() { log_header "Recreate VMs from Cloud-Init Template" echo "" if [ -z "$PVE_PASSWORD" ]; then log_error "PVE_ROOT_PASS not set in .env" exit 1 fi log_warn "This will DESTROY existing VMs (100, 101, 102, 103)" log_warn "And recreate them from a Cloud-Init template" echo "" read -p "Continue? (yes/no): " confirm if [ "$confirm" != "yes" ]; then log_info "Cancelled" exit 0 fi # Authenticate auth=$(get_ticket) if [ $? -ne 0 ]; then exit 1 fi # Step 1: Download cloud image image_file=$(download_cloud_image) if [ $? -ne 0 ]; then log_error "Failed to download cloud image" exit 1 fi # Step 2: Create template (manual steps required) create_template "$auth" "$image_file" # Verify template exists if ! template_exists "$auth"; then log_error "Template does not exist. Please create it first." exit 1 fi # Step 3: Destroy existing VMs log_header "Destroying Existing VMs" for vmid in 100 101 102 103; do destroy_vm "$auth" "$vmid" || log_warn "Failed to destroy VM $vmid" done sleep 3 # Step 4: Create VMs from template log_header "Creating VMs from Template" for vmid in 100 101 102 103; do IFS=':' read -r name cores memory disk_size ip_address gateway <<< "${VMS[$vmid]}" if create_vm_from_template "$auth" "$vmid" "$name" "$cores" "$memory" "$disk_size" "$ip_address" "$gateway"; then log_info "✓ VM $vmid created" else log_error "✗ Failed to create VM $vmid" fi echo "" done # Step 5: Start VMs log_header "Starting VMs" for vmid in 100 101 102 103; do log_info "Starting VM $vmid..." ticket=$(echo "$auth" | cut -d'|' -f1) csrf=$(echo "$auth" | cut -d'|' -f2) curl -k -s -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null 2>&1 log_info "✓ VM $vmid started" done log_header "VM Recreation Complete!" echo "" log_info "VMs are being created from template with Cloud-Init" log_info "They will boot automatically and configure themselves" log_info "No manual installation required!" echo "" log_info "Next steps:" echo " 1. Wait 2-3 minutes for VMs to boot" echo " 2. Check readiness: ./scripts/check-vm-readiness.sh" echo " 3. Run tasks: ./scripts/complete-all-vm-tasks.sh" } main "$@"