#!/usr/bin/env bash # Deploy Rina VM on a remote host running QEMU/libvirt (virsh). # Uses Debian cloud image + cloud-init for automated minimal install. # # Run on the remote machine (or from your machine with LIBVIRT_DEFAULT_URI). # Requires: libvirt, virt-install, qemu-img, genisoimage (or cloud-image-utils) set -e VM_NAME="${VM_NAME:-CUBE}" CPU="${CPU:-2}" MEMORY_GB="${MEMORY_GB:-4}" DISK_GB="${DISK_GB:-128}" # Debian 13 (Trixie) generic cloud image with cloud-init DEBIAN_IMAGE_URL="${DEBIAN_IMAGE_URL:-https://cloud.debian.org/images/cloud/trixie/latest/debian-13-generic-amd64.qcow2}" IMAGE_NAME=$(basename "$DEBIAN_IMAGE_URL") SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" CLOUD_INIT_DIR="$SCRIPT_DIR/cloud-init" POOL_DIR="${POOL_DIR:-/var/lib/libvirt/images}" BASE_IMAGE="$POOL_DIR/$IMAGE_NAME" VM_DISK="$POOL_DIR/${VM_NAME}.qcow2" SEED_ISO="$POOL_DIR/${VM_NAME}-seed.iso" # Network: libvirt virtual network (e.g. 'default') or host bridge # VLAN 40 (eth1.40 + br1.40): run systemd-networkd config on the host first, then: # BRIDGE=br1.40 ./deploy-rina-vm.sh # Other: BRIDGE=br0 or NETWORK=default NETWORK="${NETWORK:-default}" BRIDGE="${BRIDGE:-br1.40}" echo "=== Rina VM deployment ===" echo " VM name: $VM_NAME" echo " CPU: $CPU Memory: ${MEMORY_GB}G Disk: ${DISK_GB}G" echo " Base image: $DEBIAN_IMAGE_URL" echo " Pool dir: $POOL_DIR" if [[ -n "$BRIDGE" ]]; then echo " Network: bridge $BRIDGE" else echo " Network: $NETWORK" fi echo "" # 1) Ensure base image exists and resize copy for VM if [[ ! -f "$BASE_IMAGE" ]]; then echo "Downloading Debian cloud image..." sudo mkdir -p "$POOL_DIR" sudo curl -L -o "$BASE_IMAGE" "$DEBIAN_IMAGE_URL" echo "Downloaded $BASE_IMAGE" fi if [[ -f "$VM_DISK" ]]; then echo "VM disk already exists: $VM_DISK" read -p "Overwrite? (y/N) " -n 1 -r; echo if [[ ! $REPLY =~ ^[yY]$ ]]; then echo "Aborted." exit 1 fi sudo rm -f "$VM_DISK" fi echo "Creating VM disk (${DISK_GB}G) from base image..." sudo qemu-img create -f qcow2 -F qcow2 -b "$BASE_IMAGE" "$VM_DISK" sudo qemu-img resize "$VM_DISK" "${DISK_GB}G" echo "Done: $VM_DISK" # 2) Build cloud-init NoCloud seed ISO for f in user-data meta-data network-config; do if [[ ! -f "$CLOUD_INIT_DIR/$f" ]]; then echo "Missing cloud-init file: $CLOUD_INIT_DIR/$f" exit 1 fi done if command -v cloud-localds &>/dev/null; then echo "Building seed ISO with cloud-localds..." cloud-localds -v "$SEED_ISO" \ "$CLOUD_INIT_DIR/user-data" \ "$CLOUD_INIT_DIR/meta-data" else echo "Building seed ISO with genisoimage..." TMP_CI="$SCRIPT_DIR/.cloud-init-seed" mkdir -p "$TMP_CI" cp "$CLOUD_INIT_DIR/user-data" "$CLOUD_INIT_DIR/meta-data" "$TMP_CI/" sudo genisoimage -output "$SEED_ISO" -volid cidata -joliet -rock "$TMP_CI"/user-data "$TMP_CI"/meta-data rm -rf "$TMP_CI" fi echo "Seed ISO: $SEED_ISO" # 3) Create and start VM if sudo virsh list --all --name | grep -qx "$VM_NAME"; then echo "VM '$VM_NAME' already defined. Undefine it first: virsh undefine $VM_NAME" exit 1 fi echo "Creating VM..." sudo virt-install \ --name "$VM_NAME" \ --memory "$(( MEMORY_GB * 1024 ))" \ --vcpus "$CPU" \ --import \ --disk "path=$VM_DISK,format=qcow2,bus=virtio" \ --disk "path=$SEED_ISO,device=cdrom,bus=sata" \ --network "$(if [[ -n "$BRIDGE" ]]; then echo "bridge=$BRIDGE,model=virtio"; else echo "network=$NETWORK,model=virtio"; fi)" \ --os-variant debiantrixie \ --noautoconsole # 4) Dump domain XML to project directory for reference/version control VM_XML="$SCRIPT_DIR/${VM_NAME}.xml" sudo virsh dumpxml "$VM_NAME" > "$VM_XML" echo "VM definition saved to: $VM_XML" echo "" echo "VM '$VM_NAME' is starting. First boot runs cloud-init (user rina, password rinapwd; IP from cloud-init/user-data, e.g. 192.168.0.225)." echo "To open console: virsh console $VM_NAME" echo "To check: virsh list; ssh rina@ (after cloud-init finishes, ~1–2 min)."