Qemu-KVM Start Script

Just wanted to share this Bash script which I use to run my Qemu-KVM virtual machines.

 

#!/bin/bash

# License: GPLv3




################################################################################
################################################################################
# HELP SECTION

# USAGE NOTES
# - section for VM specific notes
# - e.g. VM password: some-password
# - e.g. IP on NIC 1: 1.2.3.4/24

# BASIC USAGE
#
# Tested Qemu version: 6.1.1
#
# 1. Install needed software: qemu, tmux, socat (optional)
# 2. Create a new folder. (should be one folder per VM)
#    Use one folder per VM. Put all needed file for that VM into that folder!
#    ATTENTION: The full path to that folder and the folders name should
#      only include these letters (no spaces!): A-Z a-z 0-9 _ -
# 3. Copy this script into a text file named "run.bash" inside the VM folder.
# 4. Make run.bash executeable: chmod +x run.bash
# 5. Adjust the options below.
#    Important options (most important first):
#    - ram_mb: Memory size
#    - cpus: Number of CPU cores
#    - basetime: Adjust if you're running a Windows guest.
#    - sshport and spiceport: Must be an unused TCP port!
#        (change if you run more than 1 VM simultanously)
# 6. Create HDD image inside that folder (name must be "hd0.qcow2"):
#      qemu-img create -f qcow2 hd0.qcow2 10G
# 7. Create link to or copy installation ISO (if needed).
#    Name must be: installation.iso
#    Same for "virtio-win.iso" if you're running a Windows guest. (see below)
# 8. Start run.bash. Either via filemanager or from shell: ./run.bash
# 9. If the VM doesn't start, comment out "tmux_cmd=..." and run ./bash.run
#    in a terminal to see the error output.

# CONTROL A RUNNING QEMU VM
#
# Send command via socket and get STDOUT:
#   echo 'help' | socat STDIO UNIX-CONNECT:"${mydir}"/monitor.sock; echo
#   echo 'info usb' | socat STDIO UNIX-CONNECT:"${mydir}"/monitor.sock; echo
# Send command via Tmux (no direct STDOUT feedback):
#   tmux send-keys -t "${vmname}" 'eject ide1-cd0' enter




################################################################################
################################################################################
# OPTIONS

# Get the directory this script is in.
mydir="$(dirname "$(readlink -f "${0}")")"

# Set vm name by directory name.
vmname="$(basename "${mydir}")"
# Set vm name manually.
#vmname='DebianVM'

# https://www.spice-space.org/multiple-clients.html
#   This feature is still experimental, it is not expected to work
#   correctly under different client bandwidths, although it should not
#   crash the server.
export SPICE_DEBUG_ALLOW_MC=1

# system qemu
qemu='qemu-system-x86_64'
# self compiled qemu
#qemu=~/'opt/qemu/bin/qemu-system-x86_64'

unset tmux_cmd
# disable tmux to see errors
tmux_cmd="tmux new -d -s ${vmname} "

# - guest os specific settings -
# Linux / UNIX BIOS clock mode
basetime=utc
# Windows time and driver CD (Linux has all drivers)
# Driver CD download and more information:
#   https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso
#   https://docs.fedoraproject.org/en-US/quick-docs/creating-windows-virtual-machines-using-virtio-drivers/index.html
#basetime=localtime

# host ssh port forwarding
# connect via:
#   ssh -p 50022 root@127.0.0.1
sshport=50022

# Spice (much better than VNC)
# connect via:
#   spicy -h 127.0.0.1 -p 55900
spiceport=55900
# password
spicepw='secure'

# memory (RAM) in MB (G postfix for GB - e.g.: ram_mb=2G)
ram_mb=2048
# actual memory in MB if guests has memory balloon driver (no postfix, only MB allowed!)
#balloon_mb=1536
# Disable balloon if guest has out of memory error (guest gets full ram_mb).
deflate_on_oom=false

# CPU cores
cpus=2

# -vga (high resolution)
#   Linux: virtio, std, vmware, cirrus
#   Windows: qxl, std

# Add the following lines to get a direct network interface.
# You can also bridge tap0 via "brctl".
# You must create the virtual interface in advance on the host.
#   sudo ip tuntap add dev tap0 mode tap user "${USER}"
#
#-device virtio-net-pci,mac=52:54:00:00:00:02,netdev=tap.2 \
#-netdev tap,script=no,downscript=no,ifname=tap0,id=tap.2 \




################################################################################
################################################################################
#  PRE-START

# SMB/CIFS network share: \\10.0.2.4\qemu
if [ ! -e "${mydir}"/shared-folder ]; then
	mkdir "${mydir}"/shared-folder
fi

inst_iso="${mydir}/installation.iso"
inst_iso_cmd=''
if [ -f "${inst_iso}" ]; then
	inst_iso_cmd=",format=raw,file=${inst_iso}"
fi

virtio_iso="${mydir}/virtio-win.iso"
virtio_iso_cmd=()
if [ -f "${virtio_iso}" ]; then
	virtio_iso_cmd[0]='-drive'
	virtio_iso_cmd[1]="if=ide,media=cdrom,index=3,id=ide3,format=raw,file=${virtio_iso}"
fi

if [ -n "${balloon_mb}" ]; then
	bash -c "sleep 4; echo 'balloon ${balloon_mb}' | socat STDIO UNIX-CONNECT:'${mydir}'/monitor.sock >/dev/null" & disown
fi




################################################################################
################################################################################
# START QEMU

${tmux_cmd}nice ionice -c3 "${qemu}" \
\
-boot order=c,menu=on \
-drive file="${mydir}"/hd0.qcow2,discard=unmap,detect-zeroes=unmap,media=disk,if=virtio,index=0,format=qcow2,id=virtio0 \
-drive if=ide,media=cdrom,index=2,id=ide2"${inst_iso_cmd}" \
"${virtio_iso_cmd[@]}" \
\
-device virtio-net-pci,mac=52:54:00:00:00:01,netdev=user.1,id=virtio-net-pci.0 \
-netdev user,hostfwd=tcp:127.0.0.1:"${sshport}"-:22,id=user.1,hostname="${vmname}",smb="${mydir}"/shared-folder/ \
\
-object secret,id=vncsec0,data="${spicepw}" \
-spice port="${spiceport}",addr=127.0.0.1,ipv4=on,ipv6=off,disable-ticketing=on,password-secret=vncsec0 \
-device ich9-usb-ehci1,id=usb \
-device ich9-usb-uhci1,masterbus=usb.0,firstport=0,multifunction=on \
-chardev spicevmc,name=usbredir,id=usbredirchardev1 \
-device usb-redir,chardev=usbredirchardev1,id=usbredirdev1 \
\
-cpu host \
-smp "${cpus}" \
-m "${ram_mb}" \
-device virtio-balloon,id=virtio-balloon.0,deflate-on-oom="${deflate_on_oom}" \
-machine pc,mem-merge=on,accel=kvm,smm=off \
\
-vga std \
-k de \
-device nec-usb-xhci,id=xhci \
-usb \
-device usb-tablet,id=usb-tablet.0 \
-rtc base="${basetime}" \
\
-nodefaults \
-monitor vc \
-monitor stdio \
-monitor unix:"${mydir}"/monitor.sock,server,nowait \
-serial vc \
\
-display gtk,gl=on,zoom-to-fit=off,window-close=off \
-name "${vmname}" \