diff --git a/tools/VM_README.md b/tools/VM_README.md new file mode 100644 index 0000000..2cf5f82 --- /dev/null +++ b/tools/VM_README.md @@ -0,0 +1,295 @@ +# Ubuntu VM Management with Cloud Hypervisor + +This directory contains scripts for creating and managing Ubuntu VMs using Cloud Hypervisor with btrfs thin provisioning. + +## Scripts Overview + +1. **`ubuntu_vm_start.sh`** - Creates and starts new VMs +2. **`ubuntu_vm_manage.sh`** - Manages existing VMs (list, status, console, stop, etc.) +3. **`setup_vm_network.sh`** - Sets up networking for SSH access to VMs + +## Prerequisites + +- Root access +- Btrfs filesystem (script will detect and guide setup) +- Cloud Hypervisor installed +- Basic networking tools + +## Quick Start + +### 1. Set up networking (one-time setup) +```bash +sudo ./setup_vm_network.sh +``` + +### 2. Create and start a VM +```bash +sudo ./ubuntu_vm_start.sh my-vm 2048 2 +``` +This creates a VM named "my-vm" with 2GB RAM and 2 CPU cores. + +### 3. List all VMs +```bash +sudo ./ubuntu_vm_manage.sh list +``` + +### 4. Connect to VM console +```bash +sudo ./ubuntu_vm_manage.sh console my-vm +``` + +## Detailed Usage + +### Creating VMs + +```bash +sudo ./ubuntu_vm_start.sh +``` + +**Examples:** +```bash +# Create a small VM +sudo ./ubuntu_vm_start.sh test-vm 1024 1 + +# Create a larger VM +sudo ./ubuntu_vm_start.sh dev-vm 4096 4 +``` + +**What happens:** +- Downloads Ubuntu 24.04 cloud image (first time only) +- Creates btrfs subvolumes for thin provisioning +- Sets up cloud-init with default user +- Creates network interfaces +- Starts the VM with Cloud Hypervisor + +### Managing VMs + +```bash +sudo ./ubuntu_vm_manage.sh [vm_name] +``` + +**Available commands:** + +| Command | Description | Example | +|---------|-------------|---------| +| `list` | Show all VMs and their status | `./ubuntu_vm_manage.sh list` | +| `status ` | Detailed status of specific VM | `./ubuntu_vm_manage.sh status my-vm` | +| `console ` | Connect to VM console | `./ubuntu_vm_manage.sh console my-vm` | +| `stop ` | Stop a running VM | `./ubuntu_vm_manage.sh stop my-vm` | +| `delete ` | Delete VM completely | `./ubuntu_vm_manage.sh delete my-vm` | +| `ssh ` | Show SSH connection info | `./ubuntu_vm_manage.sh ssh my-vm` | + +### Accessing VMs + +#### Method 1: Console Access (Always Available) +```bash +sudo ./ubuntu_vm_manage.sh console my-vm +``` +- Direct serial console access +- No network required +- Press `Ctrl+A` then `X` to exit +- Default login: `ubuntu` / `ubuntu` + +#### Method 2: SSH Access (Requires Network Setup) +1. Set up networking first: + ```bash + sudo ./setup_vm_network.sh + ``` + +2. Find VM IP address: + ```bash + vm-ips + # or + arp -a | grep 192.168.100 + ``` + +3. SSH to the VM: + ```bash + ssh ubuntu@192.168.100.X + ``` + Default password: `ubuntu` + +## Network Configuration + +The `setup_vm_network.sh` script configures: + +- **Bridge interface**: `br0` with IP `192.168.100.1/24` +- **DHCP server**: Assigns IPs `192.168.100.10-100` to VMs +- **NAT**: Enables internet access for VMs +- **DNS**: Uses Google DNS (8.8.8.8, 8.8.4.4) + +### Network Troubleshooting + +1. **Check bridge status:** + ```bash + ip addr show br0 + ``` + +2. **Check VM IP assignments:** + ```bash + vm-ips + ``` + +3. **Check DHCP leases:** + ```bash + cat /var/lib/dhcp/dhcpd.leases + ``` + +4. **Restart networking:** + ```bash + systemctl restart dnsmasq + ``` + +## Storage (Btrfs) + +VMs use btrfs subvolumes for efficient storage: + +- **Base image**: Shared read-only Ubuntu image +- **VM snapshots**: Copy-on-write clones for each VM +- **Thin provisioning**: Only changed blocks use disk space + +### Storage locations: +- Base images: `/var/lib/vms/base/` +- VM instances: `/var/lib/vms/vms//` + +### Storage commands: +```bash +# List subvolumes +btrfs subvolume list /var/lib/vms + +# Show space usage +btrfs filesystem usage /var/lib/vms + +# Show individual VM sizes +du -sh /var/lib/vms/vms/* +``` + +## VM Configuration + +### Default VM Setup: +- **OS**: Ubuntu 24.04 LTS +- **User**: `ubuntu` (password: `ubuntu`) +- **Sudo**: Passwordless sudo enabled +- **SSH**: Enabled with password authentication +- **Packages**: curl, wget, git, htop, vim pre-installed + +### Customizing VMs: +Edit the cloud-init configuration in `ubuntu_vm_start.sh` to: +- Add SSH keys +- Install additional packages +- Set custom passwords +- Configure services + +## Troubleshooting + +### VM won't start: +1. Check if Cloud Hypervisor is installed: + ```bash + which cloud-hypervisor + ``` + +2. Check btrfs filesystem: + ```bash + btrfs filesystem show /var/lib/vms + ``` + +3. Check available resources: + ```bash + free -h + nproc + ``` + +### Can't connect to VM: +1. Verify VM is running: + ```bash + ./ubuntu_vm_manage.sh status my-vm + ``` + +2. Try console access first: + ```bash + ./ubuntu_vm_manage.sh console my-vm + ``` + +3. Check network setup: + ```bash + ip addr show br0 + vm-ips + ``` + +### VM is slow or unresponsive: +1. Check host resources: + ```bash + top + iostat + ``` + +2. Adjust VM resources: + - Stop VM: `./ubuntu_vm_manage.sh stop my-vm` + - Delete and recreate with different specs + +## Security Notes + +- Default password is `ubuntu` - change after first login +- Consider adding SSH keys instead of password auth +- VMs have internet access through NAT +- Console access requires root privileges on host + +## Examples + +### Create a development environment: +```bash +# Set up networking +sudo ./setup_vm_network.sh + +# Create VM +sudo ./ubuntu_vm_start.sh dev-env 4096 4 + +# Wait for boot, then connect +sudo ./ubuntu_vm_manage.sh console dev-env + +# Inside VM, change password and install tools +passwd +sudo apt update && sudo apt install -y build-essential nodejs npm +``` + +### Create multiple VMs: +```bash +# Create web server +sudo ./ubuntu_vm_start.sh web-server 2048 2 + +# Create database server +sudo ./ubuntu_vm_start.sh db-server 4096 2 + +# Create load balancer +sudo ./ubuntu_vm_start.sh lb 1024 1 + +# List all VMs +sudo ./ubuntu_vm_manage.sh list +``` + +## Performance Tips + +1. **Use appropriate VM sizing** - Don't over-allocate resources +2. **Monitor host resources** - Ensure sufficient RAM/CPU +3. **Use btrfs compression** - Add `compress=zstd` mount option +4. **Regular cleanup** - Delete unused VMs to free space +5. **SSD storage** - Use SSD for better I/O performance + +## Backup and Recovery + +### Backup a VM: +```bash +# Stop VM first +sudo ./ubuntu_vm_manage.sh stop my-vm + +# Create snapshot +sudo btrfs subvolume snapshot /var/lib/vms/vms/my-vm /var/lib/vms/backups/my-vm-$(date +%Y%m%d) +``` + +### Restore from backup: +```bash +# Delete current VM +sudo ./ubuntu_vm_manage.sh delete my-vm + +# Restore from snapshot +sudo btrfs subvolume snapshot /var/lib/vms/backups/my-vm-20231215 /var/lib/vms/vms/my-vm \ No newline at end of file diff --git a/tools/install_cloudhypervisor.sh b/tools/install_cloudhypervisor.sh index 8eaa6e9..5f486f4 100755 --- a/tools/install_cloudhypervisor.sh +++ b/tools/install_cloudhypervisor.sh @@ -175,4 +175,6 @@ if command -v cloud-hypervisor &> /dev/null; then fi else error "Cloud Hypervisor installation failed. Binary not found in PATH." -fi \ No newline at end of file +fi + +apt update && apt install -y genisoimage \ No newline at end of file diff --git a/tools/setup_vm_network.sh b/tools/setup_vm_network.sh new file mode 100755 index 0000000..dbfa442 --- /dev/null +++ b/tools/setup_vm_network.sh @@ -0,0 +1,151 @@ +#!/bin/bash + +# VM Network Setup Script +# This script sets up networking for VMs to enable SSH access + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +log() { + echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" +} + +warn() { + echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}" +} + +error() { + echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}" + exit 1 +} + +info() { + echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $1${NC}" +} + +# Check if running as root +if [ "$EUID" -ne 0 ]; then + error "This script must be run as root" +fi + +BRIDGE_NAME="br0" +BRIDGE_IP="192.168.100.1/24" +NETWORK="192.168.100.0/24" + +log "Setting up VM networking..." + +# Check if bridge already exists and has IP +if ip link show "$BRIDGE_NAME" &>/dev/null; then + if ip addr show "$BRIDGE_NAME" | grep -q "192.168.100.1"; then + info "Bridge $BRIDGE_NAME already configured with IP" + else + log "Adding IP address to existing bridge..." + ip addr add "$BRIDGE_IP" dev "$BRIDGE_NAME" + fi +else + log "Bridge $BRIDGE_NAME not found. It will be created when VMs start." +fi + +# Enable IP forwarding +log "Enabling IP forwarding..." +echo 1 > /proc/sys/net/ipv4/ip_forward + +# Make IP forwarding persistent +if ! grep -q "net.ipv4.ip_forward=1" /etc/sysctl.conf; then + echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf + log "IP forwarding made persistent in /etc/sysctl.conf" +fi + +# Set up NAT for VM network +log "Setting up NAT for VM network..." + +# Remove existing rules to avoid duplicates +iptables -t nat -D POSTROUTING -s "$NETWORK" -j MASQUERADE 2>/dev/null || true +iptables -D FORWARD -i "$BRIDGE_NAME" -o "$BRIDGE_NAME" -j ACCEPT 2>/dev/null || true +iptables -D FORWARD -i "$BRIDGE_NAME" -j ACCEPT 2>/dev/null || true +iptables -D FORWARD -o "$BRIDGE_NAME" -j ACCEPT 2>/dev/null || true + +# Add new rules +iptables -t nat -A POSTROUTING -s "$NETWORK" -j MASQUERADE +iptables -A FORWARD -i "$BRIDGE_NAME" -o "$BRIDGE_NAME" -j ACCEPT +iptables -A FORWARD -i "$BRIDGE_NAME" -j ACCEPT +iptables -A FORWARD -o "$BRIDGE_NAME" -j ACCEPT + +log "NAT rules configured" + +# Install and configure dnsmasq for DHCP +if ! command -v dnsmasq &>/dev/null; then + log "Installing dnsmasq for DHCP..." + apt update && apt install -y dnsmasq +fi + +# Configure dnsmasq for VM network +DNSMASQ_CONF="/etc/dnsmasq.d/vm-network.conf" +log "Configuring DHCP for VM network..." + +cat > "$DNSMASQ_CONF" << EOF +# VM Network DHCP Configuration +# Only bind to the bridge interface to avoid conflicts with systemd-resolved +interface=$BRIDGE_NAME +bind-interfaces + +# Disable DNS server functionality (only DHCP) +port=0 + +# DHCP configuration +dhcp-range=192.168.100.10,192.168.100.100,12h +dhcp-option=3,192.168.100.1 +dhcp-option=6,8.8.8.8,8.8.4.4 + +# Disable reading /etc/hosts and /etc/resolv.conf +no-hosts +no-resolv +EOF + +# Restart dnsmasq +systemctl restart dnsmasq +systemctl enable dnsmasq + +log "DHCP server configured and started" + +# Create a script to show VM IPs +cat > "/usr/local/bin/vm-ips" << 'EOF' +#!/bin/bash +echo "VM DHCP Leases:" +echo "===============" +if [ -f /var/lib/dhcp/dhcpd.leases ]; then + awk '/lease/ { ip = $2 } /client-hostname/ { hostname = $2; gsub(/[";]/, "", hostname) } /binding state active/ { print ip " - " hostname }' /var/lib/dhcp/dhcpd.leases +elif [ -f /var/lib/dhcpcd5/dhcpcd.leases ]; then + cat /var/lib/dhcpcd5/dhcpcd.leases +else + echo "DHCP lease file not found. Checking dnsmasq leases..." + if [ -f /var/lib/dhcp/dhcpd.leases ]; then + cat /var/lib/dhcp/dhcpd.leases + else + echo "No lease information available" + echo "Try: arp -a | grep 192.168.100" + fi +fi +EOF + +chmod +x /usr/local/bin/vm-ips + +log "Network setup completed!" +echo "" +info "Network Configuration Summary:" +info "- Bridge: $BRIDGE_NAME with IP $BRIDGE_IP" +info "- DHCP range: 192.168.100.10 - 192.168.100.100" +info "- DNS servers: 8.8.8.8, 8.8.4.4" +info "- NAT configured for internet access" +echo "" +info "To see VM IP addresses: vm-ips" +info "To check bridge status: ip addr show $BRIDGE_NAME" +info "To see DHCP leases: cat /var/lib/dhcp/dhcpd.leases" +echo "" +warn "Note: VMs need to be restarted to get DHCP IP addresses" \ No newline at end of file diff --git a/tools/ubuntu_vm_manage.sh b/tools/ubuntu_vm_manage.sh new file mode 100755 index 0000000..b00fdd9 --- /dev/null +++ b/tools/ubuntu_vm_manage.sh @@ -0,0 +1,392 @@ +#!/bin/bash + +# Ubuntu VM Management Script +# Usage: ubuntu_vm_manage.sh [vm_name] + +set -e + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Configuration +VM_BASE_DIR="/var/lib/vms" +VMS_SUBVOL="$VM_BASE_DIR/vms" + +log() { + echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')] $1${NC}" +} + +warn() { + echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING: $1${NC}" +} + +error() { + echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR: $1${NC}" + exit 1 +} + +info() { + echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO: $1${NC}" +} + +show_usage() { + echo "Ubuntu VM Management Script" + echo "" + echo "Usage: $0 [vm_name]" + echo "" + echo "Commands:" + echo " list - List all VMs and their status" + echo " status - Show detailed status of a specific VM" + echo " console - Connect to VM console (serial)" + echo " ssh - SSH to VM (requires network setup)" + echo " stop - Stop a running VM" + echo " start - Start a stopped VM" + echo " delete - Delete a VM completely" + echo " ip - Show VM IP address" + echo " logs - Show VM logs" + echo "" + echo "Examples:" + echo " $0 list" + echo " $0 status test-vm" + echo " $0 console test-vm" + echo " $0 ssh test-vm" +} + +list_vms() { + log "Listing all VMs..." + echo "" + printf "%-15s %-10s %-8s %-15s %-20s\n" "VM NAME" "STATUS" "PID" "MEMORY" "STARTED" + printf "%-15s %-10s %-8s %-15s %-20s\n" "-------" "------" "---" "------" "-------" + + if [ ! -d "$VMS_SUBVOL" ]; then + warn "No VMs directory found at $VMS_SUBVOL" + return + fi + + for vm_dir in "$VMS_SUBVOL"/*; do + if [ -d "$vm_dir" ]; then + vm_name=$(basename "$vm_dir") + vm_info_file="$vm_dir/vm-info.txt" + + if [ -f "$vm_info_file" ]; then + # Safely source the file with error handling + if source "$vm_info_file" 2>/dev/null; then + # Check if VM is running + if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then + status="${GREEN}RUNNING${NC}" + 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 + + printf "%-15s %-18s %-8s %-15s %-20s\n" "$vm_name" "$(printf "%b" "$status")" "$pid" "${MEMORY_MB}MB" "$STARTED" + else + printf "%-15s %-18s %-8s %-15s %-20s\n" "$vm_name" "$(printf "%b" "${RED}ERROR${NC}")" "N/A" "N/A" "Config Error" + fi + else + printf "%-15s %-18s %-8s %-15s %-20s\n" "$vm_name" "$(printf "%b" "${YELLOW}UNKNOWN${NC}")" "N/A" "N/A" "N/A" + fi + fi + done + echo "" +} + +show_vm_status() { + local vm_name="$1" + local vm_dir="$VMS_SUBVOL/$vm_name" + local vm_info_file="$vm_dir/vm-info.txt" + + if [ ! -d "$vm_dir" ]; then + error "VM '$vm_name' not found" + fi + + if [ ! -f "$vm_info_file" ]; then + error "VM info file not found for '$vm_name'" + fi + + source "$vm_info_file" + + log "VM Status for: $vm_name" + echo "" + echo "VM Name: $VM_NAME" + echo "Memory: ${MEMORY_MB}MB" + echo "CPU Cores: $CPU_CORES" + echo "Started: $STARTED" + echo "Image Path: $VM_IMAGE_PATH" + echo "Cloud-init: $CLOUD_INIT_PATH" + echo "Socket: $VM_SOCKET" + echo "TAP Interface: $TAP_NAME" + echo "Bridge: $BRIDGE_NAME" + + # Check if VM is running + if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then + echo "Status: ${GREEN}RUNNING${NC} (PID: $VM_PID)" + + # Show network info + if ip link show "$TAP_NAME" &>/dev/null; then + echo "Network: ${GREEN}TAP interface active${NC}" + else + echo "Network: ${RED}TAP interface not found${NC}" + fi + + # Show socket info + if [ -S "$VM_SOCKET" ]; then + echo "API Socket: ${GREEN}Available${NC}" + else + echo "API Socket: ${RED}Not available${NC}" + fi + else + echo "Status: ${RED}STOPPED${NC}" + fi + echo "" +} + +connect_console() { + local vm_name="$1" + local vm_dir="$VMS_SUBVOL/$vm_name" + local vm_info_file="$vm_dir/vm-info.txt" + + if [ ! -f "$vm_info_file" ]; then + error "VM '$vm_name' not found" + fi + + source "$vm_info_file" + + if [ -z "$VM_PID" ] || ! kill -0 "$VM_PID" 2>/dev/null; then + error "VM '$vm_name' is not running" + fi + + info "Connecting to console for VM '$vm_name'" + info "Press Ctrl+A then X to exit console" + echo "" + + # Connect to the VM's console via the API socket + if [ -S "$VM_SOCKET" ]; then + # Use socat to connect to the console + if command -v socat &>/dev/null; then + socat - UNIX-CONNECT:"$VM_SOCKET" + else + warn "socat not found. Installing..." + apt update && apt install -y socat + socat - UNIX-CONNECT:"$VM_SOCKET" + fi + else + error "VM socket not found at $VM_SOCKET" + fi +} + +ssh_to_vm() { + local vm_name="$1" + + warn "SSH connection requires:" + warn "1. VM to be fully booted" + warn "2. Network bridge configured with IP" + warn "3. VM to have received IP via DHCP" + echo "" + info "To set up networking:" + 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 "SSH command: ssh ubuntu@" +} + +stop_vm() { + local vm_name="$1" + local vm_dir="$VMS_SUBVOL/$vm_name" + local vm_info_file="$vm_dir/vm-info.txt" + + if [ ! -f "$vm_info_file" ]; then + error "VM '$vm_name' not found" + fi + + source "$vm_info_file" + + if [ -z "$VM_PID" ] || ! kill -0 "$VM_PID" 2>/dev/null; then + warn "VM '$vm_name' is not running" + return + fi + + log "Stopping VM '$vm_name' (PID: $VM_PID)..." + + # Graceful shutdown first + kill -TERM "$VM_PID" 2>/dev/null || true + + # Wait a bit for graceful shutdown + sleep 3 + + # Force kill if still running + if kill -0 "$VM_PID" 2>/dev/null; then + warn "Forcing shutdown..." + kill -KILL "$VM_PID" 2>/dev/null || true + fi + + # Cleanup network + if [ -n "$TAP_NAME" ]; then + ip link delete "$TAP_NAME" 2>/dev/null || true + fi + + # Remove socket + if [ -n "$VM_SOCKET" ]; then + rm -f "$VM_SOCKET" + fi + + log "VM '$vm_name' stopped" +} + +delete_vm() { + local vm_name="$1" + local vm_dir="$VMS_SUBVOL/$vm_name" + + if [ ! -d "$vm_dir" ]; then + error "VM '$vm_name' not found" + fi + + # Stop VM first if running + if [ -f "$vm_dir/vm-info.txt" ]; then + source "$vm_dir/vm-info.txt" + if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then + log "Stopping VM before deletion..." + stop_vm "$vm_name" + fi + fi + + # Confirm deletion + echo -e "${RED}WARNING: This will permanently delete VM '$vm_name' and all its data!${NC}" + read -p "Are you sure? (yes/no): " confirm + + if [ "$confirm" = "yes" ]; then + log "Deleting VM '$vm_name'..." + btrfs subvolume delete "$vm_dir" + log "VM '$vm_name' deleted successfully" + else + info "Deletion cancelled" + fi +} + +start_vm() { + local vm_name="$1" + local vm_dir="$VMS_SUBVOL/$vm_name" + local vm_info_file="$vm_dir/vm-info.txt" + + if [ ! -d "$vm_dir" ]; then + error "VM '$vm_name' not found" + fi + + if [ ! -f "$vm_info_file" ]; then + error "VM info file not found for '$vm_name'" + fi + + source "$vm_info_file" + + # Check if VM is already running + if [ -n "$VM_PID" ] && kill -0 "$VM_PID" 2>/dev/null; then + warn "VM '$vm_name' is already running (PID: $VM_PID)" + return + fi + + log "Starting VM '$vm_name'..." + + # Create TAP interface + if ! ip link show "$TAP_NAME" &>/dev/null; then + log "Creating TAP interface $TAP_NAME..." + ip tuntap add dev "$TAP_NAME" mode tap + ip link set dev "$TAP_NAME" up + ip link set dev "$TAP_NAME" master "$BRIDGE_NAME" + fi + + # Remove existing socket if it exists + rm -f "$VM_SOCKET" + + # Start Cloud Hypervisor in background + cloud-hypervisor \ + --api-socket "$VM_SOCKET" \ + --memory "size=${MEMORY_MB}M" \ + --cpus "boot=$CPU_CORES" \ + --kernel "/var/lib/vms/base/hypervisor-fw" \ + --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)))" \ + --serial tty \ + --console off \ + --log-file /tmp/cloud-hypervisor-$VM_NAME.log & + + NEW_VM_PID=$! + + # Update VM info file with new PID + 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 socket: $VM_SOCKET" + log "TAP interface: $TAP_NAME" + log "To connect to console: ./ubuntu_vm_manage.sh console $vm_name" +} + +# Main script logic +if [ $# -eq 0 ]; then + show_usage + exit 1 +fi + +COMMAND="$1" +VM_NAME="$2" + +case "$COMMAND" in + "list") + list_vms + ;; + "status") + if [ -z "$VM_NAME" ]; then + error "VM name required for status command" + fi + show_vm_status "$VM_NAME" + ;; + "console") + if [ -z "$VM_NAME" ]; then + error "VM name required for console command" + fi + connect_console "$VM_NAME" + ;; + "ssh") + if [ -z "$VM_NAME" ]; then + error "VM name required for ssh command" + fi + ssh_to_vm "$VM_NAME" + ;; + "stop") + if [ -z "$VM_NAME" ]; then + error "VM name required for stop command" + fi + stop_vm "$VM_NAME" + ;; + "start") + if [ -z "$VM_NAME" ]; then + error "VM name required for start command" + fi + start_vm "$VM_NAME" + ;; + "delete") + if [ -z "$VM_NAME" ]; then + error "VM name required for delete command" + fi + delete_vm "$VM_NAME" + ;; + "ip"|"logs") + warn "Command '$COMMAND' not yet implemented" + ;; + *) + error "Unknown command: $COMMAND" + show_usage + exit 1 + ;; +esac \ No newline at end of file diff --git a/tools/ubuntu_vm_start.sh b/tools/ubuntu_vm_start.sh index 2b9a000..fbd04fd 100755 --- a/tools/ubuntu_vm_start.sh +++ b/tools/ubuntu_vm_start.sh @@ -82,10 +82,13 @@ fi mkdir -p "$VM_BASE_DIR" # Check if the base directory is on btrfs -if ! btrfs filesystem show "$VM_BASE_DIR" &>/dev/null; then - error "Base directory $VM_BASE_DIR is not on a btrfs filesystem. Please create a btrfs filesystem first." +FILESYSTEM_TYPE=$(stat -f -c %T "$VM_BASE_DIR" 2>/dev/null) +if [ "$FILESYSTEM_TYPE" != "btrfs" ]; then + error "Base directory $VM_BASE_DIR is not on a btrfs filesystem (detected: $FILESYSTEM_TYPE). Please create a btrfs filesystem first." fi +log "Btrfs filesystem detected at $VM_BASE_DIR" + # Create base and vms subvolumes if they don't exist if [ ! -d "$BASE_SUBVOL" ]; then log "Creating base subvolume at $BASE_SUBVOL" @@ -240,12 +243,11 @@ cloud-hypervisor \ --memory "size=${MEMORY_MB}M" \ --cpus "boot=$CPU_CORES" \ --kernel "$FIRMWARE_PATH" \ - --disk "path=$VM_IMAGE_PATH" \ - --disk "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)))" \ --serial tty \ --console off \ - --log-level info & + --log-file /tmp/cloud-hypervisor-$VM_NAME.log & VM_PID=$! @@ -266,7 +268,7 @@ MEMORY_MB=$MEMORY_MB CPU_CORES=$CPU_CORES VM_IMAGE_PATH=$VM_IMAGE_PATH CLOUD_INIT_PATH=$CLOUD_INIT_PATH -STARTED=$(date) +STARTED="$(date '+%Y-%m-%d %H:%M:%S')" EOF log "VM information saved to $VM_INFO_FILE"