#!/bin/bash source ~/.bashrc # Recreate VMs with Proper SSH Key Configuration # Destroys existing VMs and recreates them with cloud-init SSH keys set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" # Load environment variables if [ -f "$PROJECT_ROOT/.env" ]; then set -a source <(grep -v '^#' "$PROJECT_ROOT/.env" | grep -v '^$' | sed 's/#.*$//' | grep '=') set +a fi # Colors RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' log_info() { echo -e "${GREEN}[INFO]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } log_step() { echo "" echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}$1${NC}" echo -e "${BLUE}========================================${NC}" echo "" } PVE_USERNAME="${PVE_USERNAME:-root@pam}" PVE_PASSWORD="${PVE_ROOT_PASS:-}" PROXMOX_URL="${PROXMOX_ML110_URL:-https://192.168.1.206:8006}" PROXMOX_NODE="${PROXMOX_NODE:-pve}" TEMPLATE_VMID="${TEMPLATE_VMID:-9000}" SSH_KEY_FILE="$HOME/.ssh/id_ed25519_proxmox.pub" GATEWAY="${GATEWAY:-192.168.1.254}" # VM definitions: vmid name ip cores memory disk_size VMS=( "100 cloudflare-tunnel 192.168.1.188 2 2048 20" "101 k3s-master 192.168.1.60 4 4096 40" "102 git-server 192.168.1.121 2 2048 30" "103 observability 192.168.1.82 2 2048 30" ) get_api_token() { local response=$(curl -s -k --connect-timeout 10 --max-time 15 \ -d "username=$PVE_USERNAME&password=$PVE_PASSWORD" \ "$PROXMOX_URL/api2/json/access/ticket" 2>&1) if echo "$response" | grep -q '"data"'; then local ticket=$(echo "$response" | grep -o '"ticket":"[^"]*' | cut -d'"' -f4) local csrf_token=$(echo "$response" | grep -o '"CSRFPreventionToken":"[^"]*' | cut -d'"' -f4) echo "$ticket|$csrf_token" else echo "" fi } destroy_vm() { local vmid=$1 local name=$2 log_info "Destroying VM $vmid ($name)..." local tokens=$(get_api_token) if [ -z "$tokens" ]; then log_error "Failed to authenticate with Proxmox" return 1 fi local ticket=$(echo "$tokens" | cut -d'|' -f1) local csrf_token=$(echo "$tokens" | cut -d'|' -f2) # Stop VM if running local status=$(curl -s -k -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/current" | \ python3 -c "import sys, json; print(json.load(sys.stdin).get('data', {}).get('status', 'stopped'))" 2>/dev/null || echo "stopped") if [ "$status" = "running" ]; then log_info "Stopping VM $vmid..." curl -s -k -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/stop" > /dev/null sleep 5 fi # Delete VM log_info "Deleting VM $vmid..." curl -s -k -X DELETE \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid" > /dev/null log_info "VM $vmid destroyed" } create_vm_with_ssh() { local vmid=$1 local name=$2 local ip=$3 local cores=$4 local memory=$5 local disk_size=$6 log_info "Creating VM $vmid: $name with SSH keys" local tokens=$(get_api_token) if [ -z "$tokens" ]; then log_error "Failed to authenticate with Proxmox" return 1 fi local ticket=$(echo "$tokens" | cut -d'|' -f1) local csrf_token=$(echo "$tokens" | cut -d'|' -f2) # Read SSH public key if [ ! -f "$SSH_KEY_FILE" ]; then log_error "SSH key file not found: $SSH_KEY_FILE" return 1 fi local ssh_key_content=$(cat "$SSH_KEY_FILE") local ssh_key_b64=$(echo "$ssh_key_content" | base64 -w 0) # Check if template exists local template_check=$(curl -s -k -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_VMID/status/current" 2>&1) if ! echo "$template_check" | grep -q '"data"'; then log_error "Template VM $TEMPLATE_VMID not found" return 1 fi # Clone VM from template log_info "Cloning from template $TEMPLATE_VMID..." local clone_response=$(curl -s -k -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ -d "newid=$vmid" \ -d "name=$name" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$TEMPLATE_VMID/clone" 2>&1) if ! echo "$clone_response" | grep -q '"data"'; then log_error "Failed to clone VM: $clone_response" return 1 fi log_info "VM cloned, waiting for clone to complete..." sleep 10 # Configure VM log_info "Configuring VM $vmid..." # Set resources curl -s -k -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ -d "cores=$cores" \ -d "memory=$memory" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null # Configure cloud-init with SSH keys log_info "Configuring cloud-init with SSH keys..." curl -s -k -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ --data-urlencode "ipconfig0=ip=$ip/24,gw=$GATEWAY" \ --data-urlencode "ciuser=ubuntu" \ --data-urlencode "sshkeys=$ssh_key_b64" \ --data-urlencode "agent=1" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/config" > /dev/null log_info "✓ VM $vmid configured with SSH keys" # Start VM log_info "Starting VM $vmid..." curl -s -k -X POST \ -H "Cookie: PVEAuthCookie=$ticket" \ -H "CSRFPreventionToken: $csrf_token" \ "$PROXMOX_URL/api2/json/nodes/$PROXMOX_NODE/qemu/$vmid/status/start" > /dev/null log_info "✓ VM $vmid started" } main() { log_step "Recreate VMs with SSH Key Configuration" if [ ! -f "$SSH_KEY_FILE" ]; then log_error "SSH key file not found: $SSH_KEY_FILE" exit 1 fi log_warn "This will DESTROY and RECREATE all 4 VMs (100-103)" log_warn "All data on these VMs will be lost!" echo "" read -p "Are you sure you want to continue? (yes/no): " confirm if [ "$confirm" != "yes" ]; then log_info "Cancelled" exit 0 fi # Destroy existing VMs log_step "Step 1: Destroying Existing VMs" for vm_spec in "${VMS[@]}"; do read -r vmid name ip cores memory disk_size <<< "$vm_spec" destroy_vm "$vmid" "$name" || log_warn "Failed to destroy VM $vmid" done sleep 5 # Create new VMs with SSH keys log_step "Step 2: Creating VMs with SSH Keys" for vm_spec in "${VMS[@]}"; do read -r vmid name ip cores memory disk_size <<< "$vm_spec" create_vm_with_ssh "$vmid" "$name" "$ip" "$cores" "$memory" "$disk_size" || { log_error "Failed to create VM $vmid" continue } done log_step "Step 3: Waiting for VMs to Boot" log_info "Waiting 60 seconds for VMs to boot and apply cloud-init..." sleep 60 log_step "Step 4: Testing SSH Access" log_info "Testing SSH access to VMs..." local all_ok=true for vm_spec in "${VMS[@]}"; do read -r vmid name ip cores memory disk_size <<< "$vm_spec" if ssh -i "${SSH_KEY_FILE%.pub}" -o ConnectTimeout=10 -o StrictHostKeyChecking=no ubuntu@$ip "echo 'SSH OK' && hostname" &>/dev/null; then log_info " ✓ VM $vmid ($name) at $ip: SSH working" else log_error " ✗ VM $vmid ($name) at $ip: SSH not working" all_ok=false fi done if [ "$all_ok" = true ]; then log_info "" log_info "✓ All VMs recreated successfully with SSH access!" log_info "You can now run: ./scripts/deploy/complete-all-next-steps.sh" else log_warn "" log_warn "Some VMs may need more time to boot. Wait a few minutes and test again." fi } main "$@"