Initial commit: Rina VM deployment (VLAN 40, br1.40, cloud-init)

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-02-17 15:09:54 +02:00
commit d670e8cd85
8 changed files with 555 additions and 0 deletions

114
deploy-rina-vm.sh Normal file
View File

@@ -0,0 +1,114 @@
#!/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:-rina}"
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 192.168.40.225 on VLAN 40 / br1.40)."
echo "To open console: virsh console $VM_NAME"
echo "To check: virsh list; ssh rina@192.168.40.225 (after cloud-init finishes, ~12 min)."