This commit is contained in:
kristof 2025-06-15 19:42:01 +02:00
parent d336f36929
commit 3dbd0d0aea
3 changed files with 266 additions and 113 deletions

61
tools/extract_kernel.sh Executable file
View File

@ -0,0 +1,61 @@
#!/bin/bash
# Extract kernel and initrd from Ubuntu cloud image
# This script ensures kernel boot works automatically
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
log() {
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}"
}
error() {
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}"
exit 1
}
BASE_SUBVOL="/var/lib/vms/base"
BASE_IMAGE_PATH="$BASE_SUBVOL/ubuntu-24.04-server-cloudimg-amd64.raw"
KERNEL_PATH="$BASE_SUBVOL/vmlinuz"
INITRD_PATH="$BASE_SUBVOL/initrd.img"
# Check if kernel and initrd already exist
if [ -f "$KERNEL_PATH" ] && [ -f "$INITRD_PATH" ]; then
log "Kernel and initrd already extracted"
exit 0
fi
# Check if base image exists
if [ ! -f "$BASE_IMAGE_PATH" ]; then
error "Base image not found at $BASE_IMAGE_PATH"
fi
log "Extracting kernel and initrd from base image..."
# Create temporary mount point
TEMP_MOUNT=$(mktemp -d)
trap "umount '$TEMP_MOUNT' 2>/dev/null || true; losetup -d /dev/loop1 2>/dev/null || true; rmdir '$TEMP_MOUNT'" EXIT
# Mount the image
losetup -P /dev/loop1 "$BASE_IMAGE_PATH"
# Mount the boot partition (partition 16 contains kernel/initrd)
mount /dev/loop1p16 "$TEMP_MOUNT"
# Copy kernel and initrd
if [ -f "$TEMP_MOUNT/vmlinuz-6.8.0-60-generic" ] && [ -f "$TEMP_MOUNT/initrd.img-6.8.0-60-generic" ]; then
cp "$TEMP_MOUNT/vmlinuz-6.8.0-60-generic" "$KERNEL_PATH"
cp "$TEMP_MOUNT/initrd.img-6.8.0-60-generic" "$INITRD_PATH"
log "✓ Kernel and initrd extracted successfully"
else
error "Kernel or initrd not found in boot partition"
fi
# Cleanup is handled by trap
log "Kernel extraction completed"

View File

@ -1,7 +1,7 @@
#!/bin/bash #!/bin/bash
# Ubuntu VM Management Script # Ubuntu VM Management Script
# Usage: ubuntu_vm_manage.sh <command> [vm_name] # Usage: ubuntu_vm_manage.sh <command> [vm_number]
set -e set -e
@ -36,65 +36,73 @@ info() {
show_usage() { show_usage() {
echo "Ubuntu VM Management Script" echo "Ubuntu VM Management Script"
echo "" echo ""
echo "Usage: $0 <command> [vm_name]" echo "Usage: $0 <command> [vm_number]"
echo "" echo ""
echo "Commands:" echo "Commands:"
echo " list - List all VMs and their status" echo " list - List all VMs and their status"
echo " status <vm_name> - Show detailed status of a specific VM" echo " status <vm_number> - Show detailed status of a specific VM"
echo " console <vm_name> - Connect to VM console (serial)" echo " console <vm_number> - Connect to VM console (serial)"
echo " ssh <vm_name> - SSH to VM (requires network setup)" echo " ssh <vm_number> - SSH to VM (requires network setup)"
echo " stop <vm_name> - Stop a running VM" echo " stop <vm_number> - Stop a running VM"
echo " start <vm_name> - Start a stopped VM" echo " start <vm_number> - Start a stopped VM"
echo " delete <vm_name> - Delete a VM completely" echo " delete <vm_number> - Delete a VM completely"
echo " ip <vm_name> - Show VM IP address" echo " ip <vm_number> - Show VM IP address"
echo " logs <vm_name> - Show VM logs" echo " logs <vm_number> - Show VM logs"
echo "" echo ""
echo "Examples:" echo "Examples:"
echo " $0 list" echo " $0 list"
echo " $0 status test-vm" echo " $0 status 1"
echo " $0 console test-vm" echo " $0 console 1"
echo " $0 ssh test-vm" echo " $0 ssh 1"
} }
list_vms() { list_vms() {
log "Listing all VMs..." log "Listing all VMs..."
echo "" echo ""
printf "%-15s %-10s %-8s %-15s %-20s\n" "VM NAME" "STATUS" "PID" "MEMORY" "STARTED" printf "%-8s %-15s %-15s %-10s %-8s %-15s %-20s\n" "VM #" "IP ADDRESS" "VM NAME" "STATUS" "PID" "MEMORY" "STARTED"
printf "%-15s %-10s %-8s %-15s %-20s\n" "-------" "------" "---" "------" "-------" printf "%-8s %-15s %-15s %-10s %-8s %-15s %-20s\n" "----" "----------" "-------" "------" "---" "------" "-------"
if [ ! -d "$VMS_SUBVOL" ]; then if [ ! -d "$VMS_SUBVOL" ]; then
warn "No VMs directory found at $VMS_SUBVOL" warn "No VMs directory found at $VMS_SUBVOL"
return return
fi fi
for vm_dir in "$VMS_SUBVOL"/*; do for vm_dir in "$VMS_SUBVOL"/vm*; do
if [ -d "$vm_dir" ]; then if [ -d "$vm_dir" ]; then
vm_name=$(basename "$vm_dir") vm_dirname=$(basename "$vm_dir")
vm_info_file="$vm_dir/vm-info.txt" # Extract number from vm directory name (vm1, vm2, etc.)
vm_number=${vm_dirname#vm}
if [[ "$vm_number" =~ ^[0-9]+$ ]]; then
vm_ip="192.168.100.$vm_number"
vm_info_file="$vm_dir/vm-info.txt"
if [ -f "$vm_info_file" ]; then if [ -f "$vm_info_file" ]; then
# Safely source the file with error handling # Safely source the file with error handling
if source "$vm_info_file" 2>/dev/null; then if source "$vm_info_file" 2>/dev/null; then
# Check if VM is running # Check if VM is running
if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then
status="${GREEN}RUNNING${NC}" status="${GREEN}RUNNING${NC}"
pid="$VM_PID" pid="$VM_PID"
else
status="${RED}STOPPED${NC}"
pid="N/A"
fi
# Handle missing or malformed STARTED field
if [ -z "$STARTED" ]; then
STARTED="Unknown"
fi
# Use VM_NAME from config, fallback to vm number
display_name="${VM_NAME:-vm$vm_number}"
printf "%-8s %-15s %-15s %-18s %-8s %-15s %-20s\n" "$vm_number" "$vm_ip" "$display_name" "$(printf "%b" "$status")" "$pid" "${MEMORY_MB}MB" "$STARTED"
else else
status="${RED}STOPPED${NC}" printf "%-8s %-15s %-15s %-18s %-8s %-15s %-20s\n" "$vm_number" "$vm_ip" "vm$vm_number" "$(printf "%b" "${RED}ERROR${NC}")" "N/A" "N/A" "Config Error"
pid="N/A"
fi fi
# Handle missing or malformed STARTED field
if [ -z "$STARTED" ]; then
STARTED="Unknown"
fi
printf "%-15s %-18s %-8s %-15s %-20s\n" "$vm_name" "$(printf "%b" "$status")" "$pid" "${MEMORY_MB}MB" "$STARTED"
else else
printf "%-15s %-18s %-8s %-15s %-20s\n" "$vm_name" "$(printf "%b" "${RED}ERROR${NC}")" "N/A" "N/A" "Config Error" printf "%-8s %-15s %-15s %-18s %-8s %-15s %-20s\n" "$vm_number" "$vm_ip" "vm$vm_number" "$(printf "%b" "${YELLOW}UNKNOWN${NC}")" "N/A" "N/A" "N/A"
fi fi
else
printf "%-15s %-18s %-8s %-15s %-20s\n" "$vm_name" "$(printf "%b" "${YELLOW}UNKNOWN${NC}")" "N/A" "N/A" "N/A"
fi fi
fi fi
done done
@ -102,23 +110,30 @@ list_vms() {
} }
show_vm_status() { show_vm_status() {
local vm_name="$1" local vm_number="$1"
local vm_dir="$VMS_SUBVOL/$vm_name" local vm_dir="$VMS_SUBVOL/vm$vm_number"
local vm_info_file="$vm_dir/vm-info.txt" local vm_info_file="$vm_dir/vm-info.txt"
# Validate VM number
if ! [[ "$vm_number" =~ ^[0-9]+$ ]]; then
error "VM number must be a number"
fi
if [ ! -d "$vm_dir" ]; then if [ ! -d "$vm_dir" ]; then
error "VM '$vm_name' not found" error "VM number '$vm_number' not found"
fi fi
if [ ! -f "$vm_info_file" ]; then if [ ! -f "$vm_info_file" ]; then
error "VM info file not found for '$vm_name'" error "VM info file not found for VM number '$vm_number'"
fi fi
source "$vm_info_file" source "$vm_info_file"
log "VM Status for: $vm_name" log "VM Status for VM number: $vm_number"
echo "" echo ""
echo "VM Name: $VM_NAME" echo "VM Number: $vm_number"
echo "VM Name: ${VM_NAME:-vm$vm_number}"
echo "Static IP: 192.168.100.$vm_number"
echo "Memory: ${MEMORY_MB}MB" echo "Memory: ${MEMORY_MB}MB"
echo "CPU Cores: $CPU_CORES" echo "CPU Cores: $CPU_CORES"
echo "Started: $STARTED" echo "Started: $STARTED"
@ -152,21 +167,26 @@ show_vm_status() {
} }
connect_console() { connect_console() {
local vm_name="$1" local vm_number="$1"
local vm_dir="$VMS_SUBVOL/$vm_name" local vm_dir="$VMS_SUBVOL/vm$vm_number"
local vm_info_file="$vm_dir/vm-info.txt" local vm_info_file="$vm_dir/vm-info.txt"
# Validate VM number
if ! [[ "$vm_number" =~ ^[0-9]+$ ]]; then
error "VM number must be a number"
fi
if [ ! -f "$vm_info_file" ]; then if [ ! -f "$vm_info_file" ]; then
error "VM '$vm_name' not found" error "VM number '$vm_number' not found"
fi fi
source "$vm_info_file" source "$vm_info_file"
if [ -z "$VM_PID" ] || ! kill -0 "$VM_PID" 2>/dev/null; then if [ -z "$VM_PID" ] || ! kill -0 "$VM_PID" 2>/dev/null; then
error "VM '$vm_name' is not running" error "VM number '$vm_number' is not running"
fi fi
info "Connecting to console for VM '$vm_name'" info "Connecting to console for VM number '$vm_number'"
info "Press Ctrl+A then X to exit console" info "Press Ctrl+A then X to exit console"
echo "" echo ""
@ -186,39 +206,50 @@ connect_console() {
} }
ssh_to_vm() { ssh_to_vm() {
local vm_name="$1" local vm_number="$1"
local vm_ip="192.168.100.$vm_number"
warn "SSH connection requires:" # Validate VM number
warn "1. VM to be fully booted" if ! [[ "$vm_number" =~ ^[0-9]+$ ]]; then
warn "2. Network bridge configured with IP" error "VM number must be a number"
warn "3. VM to have received IP via DHCP" fi
echo ""
info "To set up networking:" info "Attempting SSH connection to VM number $vm_number at $vm_ip"
info "1. Configure bridge IP: ip addr add 192.168.100.1/24 dev br0"
info "2. Enable IP forwarding: echo 1 > /proc/sys/net/ipv4/ip_forward"
info "3. Set up NAT: iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -j MASQUERADE"
echo ""
info "Default login: ubuntu / ubuntu" info "Default login: ubuntu / ubuntu"
info "SSH command: ssh ubuntu@<vm-ip>" echo ""
# Try to SSH directly
if command -v sshpass &>/dev/null; then
info "Using sshpass for automatic login..."
sshpass -p 'ubuntu' ssh -o StrictHostKeyChecking=no ubuntu@"$vm_ip"
else
info "Manual SSH connection (enter password 'ubuntu'):"
ssh -o StrictHostKeyChecking=no ubuntu@"$vm_ip"
fi
} }
stop_vm() { stop_vm() {
local vm_name="$1" local vm_number="$1"
local vm_dir="$VMS_SUBVOL/$vm_name" local vm_dir="$VMS_SUBVOL/vm$vm_number"
local vm_info_file="$vm_dir/vm-info.txt" local vm_info_file="$vm_dir/vm-info.txt"
# Validate VM number
if ! [[ "$vm_number" =~ ^[0-9]+$ ]]; then
error "VM number must be a number"
fi
if [ ! -f "$vm_info_file" ]; then if [ ! -f "$vm_info_file" ]; then
error "VM '$vm_name' not found" error "VM number '$vm_number' not found"
fi fi
source "$vm_info_file" source "$vm_info_file"
if [ -z "$VM_PID" ] || ! kill -0 "$VM_PID" 2>/dev/null; then if [ -z "$VM_PID" ] || ! kill -0 "$VM_PID" 2>/dev/null; then
warn "VM '$vm_name' is not running" warn "VM number '$vm_number' is not running"
return return
fi fi
log "Stopping VM '$vm_name' (PID: $VM_PID)..." log "Stopping VM number '$vm_number' (PID: $VM_PID)..."
# Graceful shutdown first # Graceful shutdown first
kill -TERM "$VM_PID" 2>/dev/null || true kill -TERM "$VM_PID" 2>/dev/null || true
@ -242,15 +273,20 @@ stop_vm() {
rm -f "$VM_SOCKET" rm -f "$VM_SOCKET"
fi fi
log "VM '$vm_name' stopped" log "VM number '$vm_number' stopped"
} }
delete_vm() { delete_vm() {
local vm_name="$1" local vm_number="$1"
local vm_dir="$VMS_SUBVOL/$vm_name" local vm_dir="$VMS_SUBVOL/vm$vm_number"
# Validate VM number
if ! [[ "$vm_number" =~ ^[0-9]+$ ]]; then
error "VM number must be a number"
fi
if [ ! -d "$vm_dir" ]; then if [ ! -d "$vm_dir" ]; then
error "VM '$vm_name' not found" error "VM number '$vm_number' not found"
fi fi
# Stop VM first if running # Stop VM first if running
@ -258,45 +294,50 @@ delete_vm() {
source "$vm_dir/vm-info.txt" source "$vm_dir/vm-info.txt"
if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then
log "Stopping VM before deletion..." log "Stopping VM before deletion..."
stop_vm "$vm_name" stop_vm "$vm_number"
fi fi
fi fi
# Confirm deletion # Confirm deletion
echo -e "${RED}WARNING: This will permanently delete VM '$vm_name' and all its data!${NC}" echo -e "${RED}WARNING: This will permanently delete VM number '$vm_number' and all its data!${NC}"
read -p "Are you sure? (yes/no): " confirm read -p "Are you sure? (yes/no): " confirm
if [ "$confirm" = "yes" ]; then if [ "$confirm" = "yes" ]; then
log "Deleting VM '$vm_name'..." log "Deleting VM number '$vm_number'..."
btrfs subvolume delete "$vm_dir" btrfs subvolume delete "$vm_dir"
log "VM '$vm_name' deleted successfully" log "VM number '$vm_number' deleted successfully"
else else
info "Deletion cancelled" info "Deletion cancelled"
fi fi
} }
start_vm() { start_vm() {
local vm_name="$1" local vm_number="$1"
local vm_dir="$VMS_SUBVOL/$vm_name" local vm_dir="$VMS_SUBVOL/vm$vm_number"
local vm_info_file="$vm_dir/vm-info.txt" local vm_info_file="$vm_dir/vm-info.txt"
# Validate VM number
if ! [[ "$vm_number" =~ ^[0-9]+$ ]]; then
error "VM number must be a number"
fi
if [ ! -d "$vm_dir" ]; then if [ ! -d "$vm_dir" ]; then
error "VM '$vm_name' not found" error "VM number '$vm_number' not found"
fi fi
if [ ! -f "$vm_info_file" ]; then if [ ! -f "$vm_info_file" ]; then
error "VM info file not found for '$vm_name'" error "VM info file not found for VM number '$vm_number'"
fi fi
source "$vm_info_file" source "$vm_info_file"
# Check if VM is already running # Check if VM is already running
if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then
warn "VM '$vm_name' is already running (PID: $VM_PID)" warn "VM number '$vm_number' is already running (PID: $VM_PID)"
return return
fi fi
log "Starting VM '$vm_name'..." log "Starting VM number '$vm_number'..."
# Create TAP interface # Create TAP interface
if ! ip link show "$TAP_NAME" &>/dev/null; then if ! ip link show "$TAP_NAME" &>/dev/null; then
@ -309,12 +350,17 @@ start_vm() {
# Remove existing socket if it exists # Remove existing socket if it exists
rm -f "$VM_SOCKET" rm -f "$VM_SOCKET"
# Start Cloud Hypervisor in background # Start Cloud Hypervisor in background with kernel boot
KERNEL_PATH="/var/lib/vms/base/vmlinuz"
INITRD_PATH="/var/lib/vms/base/initrd.img"
cloud-hypervisor \ cloud-hypervisor \
--api-socket "$VM_SOCKET" \ --api-socket "$VM_SOCKET" \
--memory "size=${MEMORY_MB}M" \ --memory "size=${MEMORY_MB}M" \
--cpus "boot=$CPU_CORES" \ --cpus "boot=$CPU_CORES" \
--kernel "/var/lib/vms/base/hypervisor-fw" \ --kernel "$KERNEL_PATH" \
--initramfs "$INITRD_PATH" \
--cmdline "root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0" \
--disk "path=$VM_IMAGE_PATH" "path=$CLOUD_INIT_PATH,readonly=on" \ --disk "path=$VM_IMAGE_PATH" "path=$CLOUD_INIT_PATH,readonly=on" \
--net "tap=$TAP_NAME,mac=52:54:00:$(printf '%02x:%02x:%02x' $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)))" \ --net "tap=$TAP_NAME,mac=52:54:00:$(printf '%02x:%02x:%02x' $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)))" \
--serial tty \ --serial tty \
@ -326,10 +372,10 @@ start_vm() {
# Update VM info file with new PID # Update VM info file with new PID
sed -i "s/VM_PID=.*/VM_PID=$NEW_VM_PID/" "$vm_info_file" sed -i "s/VM_PID=.*/VM_PID=$NEW_VM_PID/" "$vm_info_file"
log "VM '$vm_name' started with PID $NEW_VM_PID" log "VM number '$vm_number' started with PID $NEW_VM_PID"
log "VM socket: $VM_SOCKET" log "VM socket: $VM_SOCKET"
log "TAP interface: $TAP_NAME" log "TAP interface: $TAP_NAME"
log "To connect to console: ./ubuntu_vm_manage.sh console $vm_name" log "To connect to console: ./ubuntu_vm_manage.sh console $vm_number"
} }
# Main script logic # Main script logic
@ -339,50 +385,65 @@ if [ $# -eq 0 ]; then
fi fi
COMMAND="$1" COMMAND="$1"
VM_NAME="$2" VM_NUMBER="$2"
case "$COMMAND" in case "$COMMAND" in
"list") "list")
list_vms list_vms
;; ;;
"status") "status")
if [ -z "$VM_NAME" ]; then if [ -z "$VM_NUMBER" ]; then
error "VM name required for status command" error "VM number required for status command"
fi fi
show_vm_status "$VM_NAME" show_vm_status "$VM_NUMBER"
;; ;;
"console") "console")
if [ -z "$VM_NAME" ]; then if [ -z "$VM_NUMBER" ]; then
error "VM name required for console command" error "VM number required for console command"
fi fi
connect_console "$VM_NAME" connect_console "$VM_NUMBER"
;; ;;
"ssh") "ssh")
if [ -z "$VM_NAME" ]; then if [ -z "$VM_NUMBER" ]; then
error "VM name required for ssh command" error "VM number required for ssh command"
fi fi
ssh_to_vm "$VM_NAME" ssh_to_vm "$VM_NUMBER"
;; ;;
"stop") "stop")
if [ -z "$VM_NAME" ]; then if [ -z "$VM_NUMBER" ]; then
error "VM name required for stop command" error "VM number required for stop command"
fi fi
stop_vm "$VM_NAME" stop_vm "$VM_NUMBER"
;; ;;
"start") "start")
if [ -z "$VM_NAME" ]; then if [ -z "$VM_NUMBER" ]; then
error "VM name required for start command" error "VM number required for start command"
fi fi
start_vm "$VM_NAME" start_vm "$VM_NUMBER"
;; ;;
"delete") "delete")
if [ -z "$VM_NAME" ]; then if [ -z "$VM_NUMBER" ]; then
error "VM name required for delete command" error "VM number required for delete command"
fi fi
delete_vm "$VM_NAME" delete_vm "$VM_NUMBER"
;; ;;
"ip"|"logs") "ip")
warn "Command '$COMMAND' not yet implemented" if [ -z "$VM_NUMBER" ]; then
error "VM number required for ip command"
fi
echo "VM $VM_NUMBER IP address: 192.168.100.$VM_NUMBER"
;;
"logs")
if [ -z "$VM_NUMBER" ]; then
error "VM number required for logs command"
fi
log_file="/tmp/cloud-hypervisor-vm$VM_NUMBER.log"
if [ -f "$log_file" ]; then
log "Showing logs for VM number $VM_NUMBER:"
tail -f "$log_file"
else
warn "Log file not found: $log_file"
fi
;; ;;
*) *)
error "Unknown command: $COMMAND" error "Unknown command: $COMMAND"

View File

@ -383,10 +383,36 @@ if [ ! -f "$FIRMWARE_PATH" ]; then
chmod +x "$FIRMWARE_PATH" chmod +x "$FIRMWARE_PATH"
test_step "Firmware executable check" "[ -x '$FIRMWARE_PATH' ]" test_step "Firmware executable check" "[ -x '$FIRMWARE_PATH' ]"
log "✓ Firmware downloaded to $FIRMWARE_PATH" log "✓ Firmware downloaded to $FIRMWARE_PATH"
else else
log "✓ Firmware already exists at $FIRMWARE_PATH" log "✓ Firmware already exists at $FIRMWARE_PATH"
test_file_exists "$FIRMWARE_PATH" "Firmware verification" test_file_exists "$FIRMWARE_PATH" "Firmware verification"
fi fi
# Extract kernel and initrd from base image
log "Extracting kernel and initrd for kernel boot..."
EXTRACT_SCRIPT="$(dirname "$0")/extract_kernel.sh"
if [ -f "$EXTRACT_SCRIPT" ]; then
"$EXTRACT_SCRIPT"
else
warn "Kernel extraction script not found, attempting manual extraction..."
# Fallback manual extraction
KERNEL_PATH="$BASE_SUBVOL/vmlinuz"
INITRD_PATH="$BASE_SUBVOL/initrd.img"
if [ ! -f "$KERNEL_PATH" ] || [ ! -f "$INITRD_PATH" ]; then
log "Extracting kernel and initrd manually..."
TEMP_MOUNT=$(mktemp -d)
losetup -P /dev/loop1 "$BASE_IMAGE_PATH"
mount /dev/loop1p16 "$TEMP_MOUNT"
cp "$TEMP_MOUNT/vmlinuz-6.8.0-60-generic" "$KERNEL_PATH" 2>/dev/null || true
cp "$TEMP_MOUNT/initrd.img-6.8.0-60-generic" "$INITRD_PATH" 2>/dev/null || true
umount "$TEMP_MOUNT"
losetup -d /dev/loop1
rmdir "$TEMP_MOUNT"
fi
fi
test_file_exists "$BASE_SUBVOL/vmlinuz" "Kernel extraction"
test_file_exists "$BASE_SUBVOL/initrd.img" "Initrd extraction"
# Create VM subvolume by cloning from base # Create VM subvolume by cloning from base
log "Setting up VM-specific storage..." log "Setting up VM-specific storage..."
@ -625,14 +651,19 @@ log "Generated MAC address for VM: $VM_MAC"
log "Launching Cloud Hypervisor..." log "Launching Cloud Hypervisor..."
# Try to start Cloud Hypervisor and capture any error output # Try to start Cloud Hypervisor and capture any error output
log "Starting Cloud Hypervisor with command:" log "Starting Cloud Hypervisor with kernel boot:"
log "cloud-hypervisor --api-socket $VM_SOCKET --memory size=${MEMORY_MB}M --cpus boot=$CPU_CORES --firmware $FIRMWARE_PATH --disk path=$VM_IMAGE_PATH path=$CLOUD_INIT_PATH,readonly=on --net tap=$TAP_NAME,mac=$VM_MAC --serial file=$VM_LOG_FILE --console off --event-monitor path=${VM_LOG_FILE}.events" log "cloud-hypervisor --memory size=${MEMORY_MB}M --cpus boot=$CPU_CORES --kernel $KERNEL_PATH --initramfs $INITRD_PATH --cmdline 'root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0' --disk path=$VM_IMAGE_PATH path=$CLOUD_INIT_PATH,readonly=on --net tap=$TAP_NAME,mac=$VM_MAC --serial file=$VM_LOG_FILE --console off --event-monitor path=${VM_LOG_FILE}.events"
# Use kernel boot instead of firmware boot to properly pass root device
KERNEL_PATH="$BASE_SUBVOL/vmlinuz"
INITRD_PATH="$BASE_SUBVOL/initrd.img"
# Try with API socket first, fall back without it if needed
cloud-hypervisor \ cloud-hypervisor \
--memory "size=${MEMORY_MB}M" \ --memory "size=${MEMORY_MB}M" \
--cpus "boot=$CPU_CORES" \ --cpus "boot=$CPU_CORES" \
--firmware "$FIRMWARE_PATH" \ --kernel "$KERNEL_PATH" \
--initramfs "$INITRD_PATH" \
--cmdline "root=LABEL=cloudimg-rootfs ro console=tty1 console=ttyS0" \
--disk "path=$VM_IMAGE_PATH" "path=$CLOUD_INIT_PATH,readonly=on" \ --disk "path=$VM_IMAGE_PATH" "path=$CLOUD_INIT_PATH,readonly=on" \
--net "tap=$TAP_NAME,mac=$VM_MAC" \ --net "tap=$TAP_NAME,mac=$VM_MAC" \
--serial "file=$VM_LOG_FILE" \ --serial "file=$VM_LOG_FILE" \