2020-03-15 23:13:25 +00:00
|
|
|
#!/usr/bin/env bash
|
|
|
|
|
|
|
|
function vm_delete() {
|
|
|
|
if [ -f "${disk_img}" ]; then
|
|
|
|
rm "${disk_img}"
|
2020-03-19 03:07:52 +00:00
|
|
|
echo "SUCCESS! Deleted ${disk_img}"
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
exit 0
|
|
|
|
}
|
|
|
|
|
|
|
|
function vm_restore() {
|
|
|
|
if [ -f "${disk_img_snapshot}" ]; then
|
|
|
|
mv "${disk_img_snapshot}" "${disk_img}"
|
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
echo "SUCCESS! Restored ${disk_img_snapshot}"
|
2020-03-15 23:13:25 +00:00
|
|
|
exit 0
|
|
|
|
}
|
|
|
|
|
|
|
|
function vm_snapshot() {
|
|
|
|
if [ -f "${disk_img_snapshot}" ]; then
|
|
|
|
mv "${disk_img_snapshot}" "${disk_img_snapshot}.old"
|
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
qemu-img create -b "${disk_img}" -f qcow2 "${disk_img_snapshot}" -q
|
2020-03-15 23:13:25 +00:00
|
|
|
if [ $? -eq 0 ]; then
|
2020-03-19 03:07:52 +00:00
|
|
|
echo "SUCCESS! Created ${disk_img_snapshot}"
|
2020-03-15 23:13:25 +00:00
|
|
|
else
|
2020-03-19 03:07:52 +00:00
|
|
|
echo "ERROR! Failed to create ${disk_img_snapshot}"
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
exit 0
|
|
|
|
}
|
|
|
|
|
2020-03-19 17:28:13 +00:00
|
|
|
function get_port() {
|
|
|
|
local PORT_START=22220
|
|
|
|
local PORT_RANGE=9
|
|
|
|
while true; do
|
|
|
|
local CANDIDATE=$[${PORT_START} + (${RANDOM} % ${PORT_RANGE})]
|
|
|
|
(echo "" >/dev/tcp/127.0.0.1/${CANDIDATE}) >/dev/null 2>&1
|
|
|
|
if [ $? -ne 0 ]; then
|
|
|
|
echo "${CANDIDATE}"
|
|
|
|
break
|
|
|
|
fi
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
2020-03-15 23:13:25 +00:00
|
|
|
function vm_boot() {
|
2020-03-19 15:24:27 +00:00
|
|
|
local VMNAME=$(basename ${VM} .conf)
|
2020-03-19 03:07:52 +00:00
|
|
|
local BIOS=""
|
2020-03-19 03:27:14 +00:00
|
|
|
local GL="on"
|
2020-03-19 15:26:01 +00:00
|
|
|
local VIRGL="on"
|
2020-03-19 03:27:14 +00:00
|
|
|
local UI="sdl"
|
2020-03-19 23:17:45 +00:00
|
|
|
|
|
|
|
# If QEMU has not already been selected, pick one
|
|
|
|
if [ -z "${QEMU}" ]; then
|
|
|
|
if [ -e /snap/bin/qemu-virgil ]; then
|
|
|
|
QEMU="/snap/bin/qemu-virgil"
|
|
|
|
QEMU_IMG="/snap/bin/qemu-virgil.qemu-img"
|
|
|
|
#QEMU_IMG="/usr/bin/qemu-img"
|
|
|
|
elif [ -e /usr/bin/qemu-system-x86_64 ]; then
|
|
|
|
QEMU="/usr/bin/qemu-system-x86_64"
|
|
|
|
QEMU_IMG="/usr/bin/qemu-img"
|
|
|
|
else
|
|
|
|
echo "ERROR! Could not find QEMU. Quitting."
|
|
|
|
exit 1
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
local QEMU_VER=$(${QEMU} -version | head -n1 | cut -d' ' -f4 | cut -d'(' -f1)
|
|
|
|
local QEMU_BIN=$(basename ${QEMU})
|
|
|
|
echo " - QEMU: ${QEMU} v${QEMU_VER}"
|
|
|
|
|
2020-03-19 03:07:52 +00:00
|
|
|
if [ ${ENABLE_EFI} -eq 1 ]; then
|
2020-03-19 23:17:45 +00:00
|
|
|
if [ "${QEMU_BIN}" == "qemu-virgil" ] && [ -e /snap/qemu-virgil/current/usr/share/qemu/edk2-x86_64-code.fd ] ; then
|
2020-03-19 03:07:52 +00:00
|
|
|
BIOS="-drive if=pflash,format=raw,readonly,file=/snap/qemu-virgil/current/usr/share/qemu/edk2-x86_64-code.fd"
|
2020-03-19 15:26:01 +00:00
|
|
|
VIRGL="off"
|
2020-03-19 03:07:52 +00:00
|
|
|
elif [ -e /usr/share/qemu/OVMF.fd ]; then
|
|
|
|
BIOS="-drive if=pflash,format=raw,readonly,file=/usr/share/qemu/OVMF.fd"
|
2020-03-19 15:26:01 +00:00
|
|
|
VIRGL="off"
|
2020-03-19 03:07:52 +00:00
|
|
|
else
|
|
|
|
echo " - EFI: Booting requested but no EFI firmware found."
|
|
|
|
echo " Booting from Legacy BIOS."
|
|
|
|
fi
|
|
|
|
echo " - BIOS: ${BIOS}"
|
|
|
|
else
|
|
|
|
echo " - BIOS: Legacy"
|
|
|
|
fi
|
|
|
|
|
2020-03-19 23:20:46 +00:00
|
|
|
echo " - Disk: ${disk_img} (${disk})"
|
|
|
|
# If the disk is present but doesn't appear to have an install, then
|
|
|
|
# remove it.
|
|
|
|
if [ -e ${disk_img} ]; then
|
|
|
|
local disk_curr_size=$(stat -c%s "${disk_img}")
|
|
|
|
if [ ${disk_curr_size} -le 395264 ]; then
|
|
|
|
echo " Looks unused, recreating."
|
|
|
|
rm "${disk_img}"
|
|
|
|
fi
|
|
|
|
fi
|
|
|
|
|
2020-03-19 03:07:52 +00:00
|
|
|
if [ ! -f "${disk_img}" ]; then
|
|
|
|
# If there is no disk image, create a new image.
|
2020-03-19 23:20:46 +00:00
|
|
|
${QEMU_IMG} create -q -f qcow2 "${disk_img}" "${disk}"
|
2020-03-19 15:26:21 +00:00
|
|
|
if [ $? -ne 0 ]; then
|
|
|
|
echo "ERROR! Failed to create ${disk_img} of ${disk}. Stopping here."
|
|
|
|
exit 1
|
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
echo " - ISO: ${iso}"
|
|
|
|
else
|
|
|
|
# If there is a disk image, do not boot from the iso
|
|
|
|
iso=""
|
|
|
|
fi
|
|
|
|
if [ -e ${disk_img_snapshot} ]; then
|
|
|
|
echo " - Snapshot: ${disk_img_snapshot}"
|
|
|
|
fi
|
|
|
|
|
2020-03-19 02:12:36 +00:00
|
|
|
local cores="1"
|
|
|
|
local allcores=$(nproc --all)
|
|
|
|
if [ ${allcores} -ge 8 ]; then
|
|
|
|
cores="4"
|
|
|
|
elif [ ${allcores} -ge 4 ]; then
|
|
|
|
cores="2"
|
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
echo " - CPU: ${cores} Core(s)"
|
2020-03-19 02:12:36 +00:00
|
|
|
|
|
|
|
local ram="2G"
|
|
|
|
local allram=$(free --mega -h | grep Mem | cut -d':' -f2 | cut -d'G' -f1 | sed 's/ //g')
|
|
|
|
if [ ${allram} -ge 64 ]; then
|
|
|
|
ram="4G"
|
|
|
|
elif [ ${allram} -ge 16 ]; then
|
|
|
|
ram="3G"
|
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
echo " - RAM: ${ram}"
|
2020-03-15 23:13:25 +00:00
|
|
|
|
2020-03-19 01:45:38 +00:00
|
|
|
# Determine what display to use
|
2020-03-19 03:27:14 +00:00
|
|
|
local display="-display ${UI},gl=${GL}"
|
2020-03-19 23:18:49 +00:00
|
|
|
if [ "${QEMU_VER}" == "2.11.1" ]; then
|
2020-03-19 01:45:38 +00:00
|
|
|
display="-display sdl"
|
|
|
|
# Fix stuttering mouse pointer when SDL backend is used.
|
|
|
|
export SDL_VIDEO_X11_DGAMOUSE=0
|
|
|
|
fi
|
2020-03-19 03:27:14 +00:00
|
|
|
echo " - UI: ${UI}"
|
|
|
|
echo " - GL: ${GL}"
|
2020-03-19 15:26:01 +00:00
|
|
|
echo " - VIRGL: ${VIRGL}"
|
2020-03-19 01:45:38 +00:00
|
|
|
|
2020-03-19 02:12:36 +00:00
|
|
|
# TODO: Detect Wayland here and "do the right thing".
|
2020-03-19 01:45:38 +00:00
|
|
|
# Determine the most suitable 16:9 resolution of for VM based
|
|
|
|
# on the lowest resolution connected monitor.
|
2020-03-19 02:12:36 +00:00
|
|
|
local xres=800
|
|
|
|
local yres=600
|
|
|
|
|
|
|
|
local LOWEST_WIDTH=$(xrandr --listmonitors | grep -v Monitors | cut -d' ' -f4 | cut -d'/' -f1 | sort | head -n1)
|
2020-03-19 01:45:38 +00:00
|
|
|
if [ ${LOWEST_WIDTH} -ge 3840 ]; then
|
|
|
|
xres=3200
|
|
|
|
yres=1800
|
|
|
|
elif [ ${LOWEST_WIDTH} -ge 2560 ]; then
|
|
|
|
xres=2048
|
|
|
|
yres=1152
|
|
|
|
elif [ ${LOWEST_WIDTH} -ge 1920 ]; then
|
|
|
|
xres=1664
|
|
|
|
yres=936
|
|
|
|
elif [ ${LOWEST_WIDTH} -ge 1280 ]; then
|
|
|
|
xres=1152
|
|
|
|
yres=648
|
|
|
|
fi
|
|
|
|
|
2020-03-19 23:17:45 +00:00
|
|
|
if [ "${QEMU_BIN}" == "qemu-virgil" ]; then
|
2020-03-19 03:07:52 +00:00
|
|
|
echo " - Monitor: ${xres}x${yres}"
|
2020-03-19 01:41:58 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-19 17:29:01 +00:00
|
|
|
local NET=""
|
2020-03-19 01:39:23 +00:00
|
|
|
# If smbd is available, export $HOME to the guest via samba
|
2020-03-19 23:17:45 +00:00
|
|
|
if [ "${QEMU_BIN}" == "qemu-virgil" ] && [ -e /snap/qemu-virgil/current/usr/sbin/smbd ]; then
|
2020-03-19 17:29:01 +00:00
|
|
|
NET=",smb=${HOME}"
|
2020-03-19 23:17:45 +00:00
|
|
|
elif [ "${QEMU_BIN}" == "qemu-system-x86_64" ] && [ -e /usr/sbin/smbd ]; then
|
2020-03-19 17:29:01 +00:00
|
|
|
NET=",smb=${HOME}"
|
2020-03-19 01:39:23 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-19 17:29:01 +00:00
|
|
|
if [ -n "${NET}" ]; then
|
2020-03-19 03:07:52 +00:00
|
|
|
echo " - smbd: ${HOME} will be exported to the guest via smb://10.0.2.4/qemu"
|
2020-03-19 01:39:23 +00:00
|
|
|
else
|
2020-03-19 15:26:51 +00:00
|
|
|
echo " - smbd: ${HOME} will not be exported to the guest. 'smbd' not found."
|
2020-03-19 01:39:23 +00:00
|
|
|
fi
|
|
|
|
|
2020-03-19 17:29:01 +00:00
|
|
|
# Find a free port to expose ssh to the guest
|
|
|
|
local PORT=$(get_port)
|
|
|
|
if [ -n "${PORT}" ]; then
|
|
|
|
NET="${NET},hostfwd=tcp::${PORT}-:22"
|
|
|
|
echo " - ssh: ${PORT}/tcp is connected. Login via 'ssh user@localhost -p ${PORT}'"
|
|
|
|
else
|
|
|
|
echo " - ssh: All ports for exposing ssh have been exhausted."
|
|
|
|
fi
|
|
|
|
|
2020-03-19 03:07:52 +00:00
|
|
|
#echo " - QEMU: qemu-${ENGINE}"
|
2020-03-15 23:13:25 +00:00
|
|
|
# Boot the iso image
|
2020-03-19 23:17:45 +00:00
|
|
|
${QEMU} -name ${VMNAME},process=${VMNAME} \
|
2020-03-19 15:24:27 +00:00
|
|
|
${BIOS} \
|
2020-03-15 23:13:25 +00:00
|
|
|
-cdrom "${iso}" \
|
|
|
|
-drive "file=${disk_img},format=qcow2,if=virtio,aio=native,cache.direct=on" \
|
|
|
|
-enable-kvm \
|
|
|
|
-machine q35,accel=kvm \
|
|
|
|
-cpu host,kvm=on \
|
|
|
|
-m ${ram} \
|
|
|
|
-smp ${cores} \
|
|
|
|
-net nic,model=virtio \
|
2020-03-19 17:29:01 +00:00
|
|
|
-net user"${NET}" \
|
2020-03-15 23:13:25 +00:00
|
|
|
-rtc base=localtime,clock=host \
|
2020-03-19 15:27:37 +00:00
|
|
|
-serial mon:stdio \
|
2020-03-15 23:13:25 +00:00
|
|
|
-soundhw hda \
|
|
|
|
-usb -device usb-kbd -device usb-tablet \
|
|
|
|
-object rng-random,id=rng0,filename=/dev/urandom \
|
|
|
|
-device virtio-rng-pci,rng=rng0 \
|
|
|
|
-device qemu-xhci \
|
2020-03-19 15:26:01 +00:00
|
|
|
-device virtio-vga,virgl=${VIRGL},xres=${xres},yres=${yres} \
|
2020-03-19 01:41:58 +00:00
|
|
|
${display} \
|
2020-03-19 15:28:15 +00:00
|
|
|
"$@"
|
2020-03-15 23:13:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
function usage() {
|
2020-03-19 02:07:49 +00:00
|
|
|
local LAUNCHER=$(basename $0)
|
2020-03-15 23:13:25 +00:00
|
|
|
echo
|
|
|
|
echo "Usage"
|
|
|
|
echo " ${LAUNCHER} --vm ubuntu.conf"
|
|
|
|
echo
|
|
|
|
echo "You can also pass optional parameters"
|
|
|
|
echo " --delete : Delete the disk image."
|
2020-03-19 01:41:58 +00:00
|
|
|
echo " --efi : Enable EFI BIOS (experimental)."
|
2020-03-19 23:17:45 +00:00
|
|
|
echo " --qemu : Override full path to QEMU executable."
|
2020-03-15 23:13:25 +00:00
|
|
|
echo " --restore : Restore the snapshot."
|
|
|
|
echo " --snapshot : Create a disk snapshot."
|
|
|
|
exit 1
|
|
|
|
}
|
|
|
|
|
2020-03-19 02:12:36 +00:00
|
|
|
disk="64G"
|
2020-03-19 01:41:58 +00:00
|
|
|
BIOS=""
|
2020-03-15 23:13:25 +00:00
|
|
|
DELETE=0
|
2020-03-19 01:41:58 +00:00
|
|
|
ENABLE_EFI=0
|
2020-03-19 23:17:45 +00:00
|
|
|
QEMU=""
|
2020-03-15 23:13:25 +00:00
|
|
|
RESTORE=0
|
|
|
|
SNAPSHOT=0
|
|
|
|
VM=""
|
|
|
|
|
|
|
|
while [ $# -gt 0 ]; do
|
|
|
|
case "${1}" in
|
2020-03-15 23:33:52 +00:00
|
|
|
-efi|--efi)
|
2020-03-19 01:41:58 +00:00
|
|
|
ENABLE_EFI=1
|
2020-03-15 23:33:52 +00:00
|
|
|
shift;;
|
2020-03-15 23:13:25 +00:00
|
|
|
-delete|--delete)
|
|
|
|
DELETE=1
|
|
|
|
shift;;
|
|
|
|
-restore|--restore)
|
2020-03-16 02:08:18 +00:00
|
|
|
RESTORE=1
|
2020-03-15 23:13:25 +00:00
|
|
|
shift;;
|
|
|
|
-snapshot|--snapshot)
|
|
|
|
SNAPSHOT=1
|
|
|
|
shift;;
|
2020-03-19 23:17:45 +00:00
|
|
|
-qemu|--qemu)
|
|
|
|
QEMU="$2"
|
|
|
|
shift
|
2020-03-15 23:13:25 +00:00
|
|
|
shift;;
|
|
|
|
-vm|--vm)
|
|
|
|
VM="$2"
|
|
|
|
shift
|
|
|
|
shift;;
|
|
|
|
-h|--h|-help|--help)
|
|
|
|
usage;;
|
|
|
|
*)
|
|
|
|
echo "ERROR! \"${1}\" is not a supported parameter."
|
|
|
|
usage;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
|
2020-03-19 03:07:52 +00:00
|
|
|
if [ -n "${VM}" ] || [ -e "${VM}" ]; then
|
2020-03-15 23:13:25 +00:00
|
|
|
source "${VM}"
|
2020-03-19 03:07:52 +00:00
|
|
|
echo Starting "${VM}"
|
2020-03-15 23:13:25 +00:00
|
|
|
if [ -n "${disk_img}" ]; then
|
|
|
|
disk_img_snapshot="${disk_img}.snapshot"
|
|
|
|
else
|
|
|
|
echo "ERROR! No disk_img defined."
|
|
|
|
exit 1
|
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
else
|
|
|
|
echo "ERROR! VM not found."
|
|
|
|
exit 1
|
2020-03-19 23:17:45 +00:00
|
|
|
fi
|
2020-03-19 03:07:52 +00:00
|
|
|
|
2020-03-19 23:17:45 +00:00
|
|
|
if [ -n "${QEMU}" ] && [ ! -e "${QEMU}" ]; then
|
|
|
|
echo "ERROR! ${QEMU} not found. Quitting"
|
|
|
|
exit 1
|
2020-03-15 23:13:25 +00:00
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ${DELETE} -eq 1 ]; then
|
|
|
|
vm_delete
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ${RESTORE} -eq 1 ]; then
|
|
|
|
vm_restore
|
|
|
|
fi
|
|
|
|
|
|
|
|
if [ ${SNAPSHOT} -eq 1 ]; then
|
|
|
|
vm_snapshot
|
|
|
|
fi
|
|
|
|
|
2020-03-19 23:20:58 +00:00
|
|
|
vm_boot
|