#!/bin/bash # shellcheck disable=SC2155 # shellcheck disable=SC2164 readonly script_path="$( cd -- "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )" # https://stackoverflow.com/a/4774063 # Location of the SSH config to be generated SSH_CONFIG=${SSH_CONFIG:-"$script_path/ssh.conf"} NUM_NODES=${NUM_NODES:-"2"} MEMORY=${MEMORY:-"2048"} CPU=${CPU:-"2"} DISK_MAX_SIZE=${DISK_MAX_SIZE:-"20G"} # Location of VM state information, including its persistent disk STATE_DIR=${STATE_DIR:-"$script_path/state"} # Location of Linux cloud image BASE_IMAGE_FILENAME=${BASE_IMAGE_FILENAME:-"$script_path/images/Rocky-9-GenericCloud-Base.latest.x86_64.qcow2"} # Architecture that QEMU will emulate EMU_ARCH=${EMU_ARCH:-"x86_64"} # Check for prerequisites if ! command -v mkisofs > /dev/null 2>&1; then echo "mkisofs not found." exit 1 fi if ! command -v qemu-system-"$EMU_ARCH" > /dev/null 2>&1; then echo "qemu-system-$EMU_ARCH not found." exit 1 fi stop() { for ((i=0;i/dev/null 2>&1 rm -f "$STATE_DIR"/node$i.pid done } start() { stop for ((i=0;i/dev/null 2>&1 && ((attempts_remaining > 0)); do ((attempts_remaining--)) if [ $attempts_remaining == 0 ]; then echo "SSH service on node$i took too long to be ready" exit 1 fi echo "Waiting for SSH service on node$i to be ready; $attempts_remaining attempts remaining" sleep 5 done echo "SSH service on node$i is up" done echo "To access a VM, run:" echo echo " ssh -F $SSH_CONFIG node#" echo echo "Where # is the node number you want to reach." } destroy() { stop rm -f "$STATE_DIR"/id_ed25519 rm -f "$STATE_DIR"/id_ed25519.pub rm -f "$SSH_CONFIG" for ((i=0;i/dev/null 2>&1 ssh_pubkey=$(tr -d '\n' < "$STATE_DIR"/id_ed25519.pub) for ((i=0;i "$STATE_DIR"/user-data <<- EOF #cloud-config users: - name: root ssh_authorized_keys: - $ssh_pubkey EOF cat > "$STATE_DIR"/meta-data <<- EOF instance-id: node$i local-hostname: node$i EOF cat > "$STATE_DIR"/network-config <<- EOF network: version: 2 ethernets: eth0: match: macaddress: "52:54:00:00:00:$(printf '%02x' $i)" dhcp4: false addresses: - 192.168.30.$((10 + i))/24 EOF mkisofs -o "$STATE_DIR"/node$i-cloudinit.iso -V cidata -r -J "$STATE_DIR"/user-data "$STATE_DIR"/meta-data "$STATE_DIR"/network-config >/dev/null 2>&1 rm "$STATE_DIR"/user-data rm "$STATE_DIR"/meta-data rm "$STATE_DIR"/network-config # Create main disk, backed by read-only cloud image qemu-img create -f qcow2 -F qcow2 -b "$BASE_IMAGE_FILENAME" "$STATE_DIR"/node$i.qcow2 20G >/dev/null 2>&1 # Create SSH config to be used for accessing the VM cat >> "$SSH_CONFIG" <<- EOF Host node$i StrictHostKeyChecking no UserKnownHostsFile /dev/null IdentityFile $STATE_DIR/id_ed25519 IdentitiesOnly yes User root Hostname localhost Port $((3100 + i)) EOF done start } case $1 in start) shift start "$@" ;; stop) shift stop "$@" ;; destroy) shift destroy "$@" ;; create) shift create "$@" ;; esac