#!/bin/bash ORIGINAL_ARGS=("$@") # Includes . $(miniade) || { echo "${0##*/}: ERROR: miniade failed (hint: run 'miniade' to see error)" >&2; exit 1; } # Configurable stuff # Other globals main() { local MY_ARGS local PROGNAME # Defaults for options REMOTE_HOST= MEM_SIZE=1 DISK_TUPLES=() NIC_TUPLES=() VM_NAME= CPU_COUNT=1 RELEASE= # Process options special_opts_handler() { case $1 in --name=*) VM_NAME=${1#*=} ;; --os=*) miniade_warning "'--os=' has been replaced by '--release='" RELEASE=${1#*=} ;; --release=*) RELEASE=${1#*=} ;; --remote=*) REMOTE_HOST=${1#*=} ;; --mem=*) MEM_SIZE=${1#*=} ;; --nic=*) NIC_TUPLES=( "${NIC_TUPLES[@]}" ${1#*=} ) ;; --cpus=*) CPU_COUNT=${1#*=} ;; --disk=*) DISK_TUPLES=( "${DISK_TUPLES[@]}" ${1#*=} ) ;; *) return 1 ;; esac } miniade_process_options --help-handler=help --special-opts-handler=special_opts_handler MY_ARGS "$@" && set -- "${MY_ARGS[@]}" # Process arguments [ $# = 0 ] || miniade_bad_usage # Sanity checks and derivations miniade_get_progname PROGNAME HISTFILE=$HOME/.${PROGNAME}_history for VAR in REMOTE_HOST; do eval "[ \"X\$$VAR\" != Xunset ] || $VAR=" done for VAR in VM_NAME; do eval "[ \"X\$$VAR\" != X ]" || miniade_bad_usage done export LIBVIRT_DEFAULT_URI=qemu:///system [ ${#DISK_TUPLES[*]} -ge 1 ] || miniade_bad_usage [ "X$REMOTE_HOST" = X ] || miniade_check_ssh_ok $REMOTE_HOST || miniade_error "$REMOTE_HOST: no unfettered ssh access" { ! virsh dominfo $VM_NAME > /dev/null 2>&1; } || miniade_error "$VM_NAME: VM defined locally already (hint: maybe run 'virsh undefine $VM_NAME'?)" if [ "X$REMOTE_HOST" != X ]; then miniade_check_ssh_ok $REMOTE_HOST { ! ssh -n $REMOTE_HOST "export LIBVIRT_DEFAULT_URI=$LIBVIRT_DEFAULT_URI; virsh dominfo $VM_NAME" > /dev/null 2>&1; } || miniade_error "$VM_NAME: VM defined remotely already (hint: maybe run 'ssh -n $REMOTE_HOST \"export LIBVIRT_DEFAULT_URI=$LIBVIRT_DEFAULT_URI; virsh undefine $VM_NAME\"'?)" fi # Disk checks for ((I=0; I<${#DISK_TUPLES[*]}; I++)); do [[ ${DISK_TUPLES[$I]} =~ ^(file|block):(/.*) ]] || miniade_error "${DISK_TUPLES[$I]}: failed to parse (hint: should be {file|block}:)" DISK_TYPE=${BASH_REMATCH[1]} DISK_IMAGE_OR_DEVICE=${BASH_REMATCH[2]} STAT_OUTPUT=$(stat -L -c %F $DISK_IMAGE_OR_DEVICE 2>&1) || true miniade_debug 10 "main: DISK_TYPE=$DISK_TYPE, DISK_IMAGE_OR_DEVICE=$DISK_IMAGE_OR_DEVICE, STAT_OUTPUT=[$STAT_OUTPUT]" if [ $DISK_TYPE = file ] && [ "$STAT_OUTPUT" != "regular file" ]; then miniade_error "$DISK_IMAGE_OR_DEVICE: not a file" elif [ $DISK_TYPE = block ] && [ "$STAT_OUTPUT" != "block special file" ]; then miniade_error "$DISK_IMAGE_OR_DEVICE: not a block device" fi { ! [[ $DISK_IMAGE_OR_DEVICE =~ /dev/drbd.* ]]; } || [ "X$(drbdadm status ${DISK_IMAGE_OR_DEVICE#/dev/} | sed -n '1s/.*://p')" = XPrimary ] || miniade_error "$DISK_IMAGE_OR_DEVICE: appears to be a DRBD device but not in primary mode" done DISK_LETTER_MAP=( {a..z} ) # NIC checks for ((I=0; I<${#NIC_TUPLES[*]}; I++)); do [[ ${NIC_TUPLES[$I]} =~ ^(bridge|network):(.+) ]] || miniade_error "${NIC_TUPLES[$I]}: failed to parse (hint: should be {bridge|network}:)" NIC_TYPE=${BASH_REMATCH[1]} NIC_BRIDGE_OR_NETWORK=${BASH_REMATCH[2]} done # Memory checks if [[ $MEM_SIZE =~ ^([1-9][0-9]*)([GMK]?)$ ]]; then MEM_SIZE=${BASH_REMATCH[1]} MEM_SIZE_UNIT=${BASH_REMATCH[2]:-G} else miniade_error "$MEM_SIZE: invalid memory size (hint: format is [unit])" fi # Release checks [ "X$RELEASE" != X ] || { RELEASE=bullseye; miniade_warning "release defaulted to $RELEASE (hint: use option '--release=$RELEASE' to avoid this warning or '--release=' to use another release instead)"; } case $RELEASE in bullseye) : ;; debian11) RELEASE=bullseye ;; bookworm) : ;; debian12) RELEASE=bookworm ;; trixie) : ;; debian13) RELEASE=trixie ;; stable|unstable|testing|sid) miniade_error "$RELEASE: moving-target release name (hint: use a less ambiguous release name (e.g. 'debian12' or 'bookworm')" ;; *) miniade_internal "$RELEASE: invalid release" ;; esac case $RELEASE in bullseye) ISO_FILE=/vol/local/images/debian-11.6.0-amd64-netinst.iso ;; bookworm) ISO_FILE=/vol/local/images/debian-12.6.0-amd64-netinst.iso ;; trixie) ISO_FILE=/vol/local/images/debian-trixie-DI-alpha1-amd64-netinst.iso ;; *) miniade_internal "this should not happen (1, RELEASE=$RELEASE)" ;; esac # Misc UUID=$(uuidgen) # Guts echo "$(date --iso=seconds): $0" "${ORIGINAL_ARGS[@]}" >> $HISTFILE write_xml > /tmp/$PROGNAME.$$.xml define_vm /tmp/$PROGNAME.$$.xml } help() { local PROGNAME miniade_get_progname PROGNAME echo "Usage: $PROGNAME [ ] [ --remote= ] --name= [ --release= ] [ --mem=[MGT] ] [ --cpus= ] --disk={block|file}: [ ... ] --nic={bridge|network}: [ ... ]" exit 0 } write_xml() { miniade_info "generating XML ..." DISK_OR_NIC_BUS= echo "" echo " $VM_NAME" echo " $UUID" echo " " miniade_debug 10 "write_xml: writing mounthook stuff ..." miniade_debug 10 "write_xml: writing libosinfo stuff ..." echo " " case $RELEASE in bullseye) echo " " ;; bookworm) echo " " ;; trixie) echo " " ;; *) miniade_internal "this should not happen (2)" ;; esac echo " " echo " " miniade_debug 10 "write_xml: writing memory stuff ..." case $MEM_SIZE_UNIT in G) MEM_SIZE_KB=$((MEM_SIZE*1024*1024)) ;; M) MEM_SIZE_KB=$((MEM_SIZE*1024)) ;; K) MEM_SIZE_KB=$MEM_SIZE ;; esac echo " $MEM_SIZE_KB" echo " $MEM_SIZE_KB" miniade_debug 10 "write_xml: writing cpu stuff ..." echo " $CPU_COUNT" miniade_debug 10 "write_xml: writing cgroups stuff ..." miniade_debug 10 "write_xml: writing OS stuff ..." echo " " echo " hvm" case $RELEASE in bullseye) echo " /usr/share/OVMF/OVMF_CODE.fd" ;; bookworm) echo " /usr/share/OVMF/OVMF_CODE_4M.fd" ;; trixie) echo " /usr/share/OVMF/OVMF_CODE_4M.fd" ;; *) miniade_internal "this should not happen (3)" ;; esac echo " /var/lib/libvirt/qemu/nvram/${VM_NAME}_VARS.fd" echo " " echo " " miniade_debug 10 "write_xml: writing UID/GID remapping stuff ..." miniade_debug 10 "write_xml: writing features stuff ..." echo " " echo " " echo " " echo " " echo " " miniade_debug 10 "write_xml: writing cpu stuff (should be moved for better alignment) ..." echo " " miniade_debug 10 "write_xml: writing clock stuff ..." echo " " echo " " echo " " echo " " echo " " miniade_debug 10 "write_xml: writing switch-related stuff ..." echo " destroy" echo " restart" echo " destroy" echo " " echo " " echo " " echo " " echo " " miniade_debug 10 "write_xml: writing hypervisor stuff ..." echo " /usr/bin/qemu-system-x86_64" miniade_debug 10 "write_xml: writing video stuff ..." echo "