DistroHopper/quickemu

347 lines
9.5 KiB
Plaintext
Raw Normal View History

2020-03-15 23:13:25 +00:00
#!/usr/bin/env bash
function disk_delete() {
2020-03-20 18:12:13 +00:00
if [ -e "${disk_img}" ]; then
2020-03-15 23:13:25 +00:00
rm "${disk_img}"
echo "SUCCESS! Deleted ${disk_img}"
2020-03-20 18:12:13 +00:00
else
echo "NOTE! ${disk_img} not found. Doing nothing."
2020-03-15 23:13:25 +00:00
fi
}
2020-03-20 18:17:53 +00:00
function snapshot_apply() {
local snapshot_tag="${1}"
if [ -z "${snapshot_tag}" ]; then
echo "ERROR! No snapshot tag provided."
exit
fi
if [ -e "${disk_img}" ]; then
${QEMU_IMG} snapshot -q -a "${snapshot_tag}" "${disk_img}"
if [ $? -eq 0 ]; then
echo "SUCCESS! Applied snapshot ${snapshot_tag} to ${disk_img}"
else
echo "ERROR! Failed to apply snapshot ${snapshot_id} to ${disk_img}"
fi
else
echo "NOTE! ${disk_img} not found. Doing nothing."
2020-03-15 23:13:25 +00:00
fi
}
2020-03-20 18:17:53 +00:00
function snapshot_create() {
local snapshot_tag="${1}"
if [ -z "${snapshot_tag}" ]; then
echo "ERROR! No snapshot tag provided."
exit
2020-03-15 23:13:25 +00:00
fi
2020-03-20 18:17:53 +00:00
if [ -e "${disk_img}" ]; then
${QEMU_IMG} snapshot -q -c "${snapshot_tag}" "${disk_img}"
if [ $? -eq 0 ]; then
echo "SUCCESS! Created snapshot ${snapshot_tag} of ${disk_img}"
else
echo "ERROR! Failed to create snapshot ${snapshot_tag} of ${disk_img}"
fi
2020-03-15 23:13:25 +00:00
else
2020-03-20 18:17:53 +00:00
echo "NOTE! ${disk_img} not found. Doing nothing."
fi
}
function snapshot_delete() {
local snapshot_tag="${1}"
if [ -z "${snapshot_tag}" ]; then
echo "ERROR! No snapshot tag provided."
exit
fi
if [ -e "${disk_img}" ]; then
${QEMU_IMG} snapshot -q -d "${snapshot_tag}" "${disk_img}"
if [ $? -eq 0 ]; then
echo "SUCCESS! Deleted snapshot ${snapshot_tag} of ${disk_img}"
else
echo "ERROR! Failed to delete snapshot ${snapshot_tag} of ${disk_img}"
fi
else
echo "NOTE! ${disk_img} not found. Doing nothing."
fi
}
function snapshot_info() {
if [ -e "${disk_img}" ]; then
${QEMU_IMG} info "${disk_img}"
2020-03-15 23:13:25 +00:00
fi
}
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() {
local VMNAME=$(basename ${VM} .conf)
local VMDIR=$(dirname ${disk_img})
local BIOS=""
local GL="off"
local VIRGL="on"
local UI="sdl"
local QEMU_VER=$(${QEMU} -version | head -n1 | cut -d' ' -f4 | cut -d'(' -f1)
echo "Starting ${VM}"
echo " - QEMU: ${QEMU} v${QEMU_VER}"
2020-03-20 18:16:08 +00:00
readonly disk_min_size=$((197632 * 8))
2020-03-20 13:47:34 +00:00
if [ -z "${disk}" ]; then
disk="64G"
fi
if [ ${ENABLE_EFI} -eq 1 ]; then
if [ -e /snap/qemu-virgil/current/usr/share/qemu/edk2-x86_64-code.fd ] ; then
if [ ! -e ${VMDIR}/${VMNAME}-vars.fd ]; then
cp /snap/qemu-virgil/current/usr/share/qemu/edk2-i386-vars.fd ${VMDIR}/${VMNAME}-vars.fd
fi
BIOS="-drive if=pflash,format=raw,readonly,file=/snap/qemu-virgil/current/usr/share/qemu/edk2-x86_64-code.fd -drive if=pflash,format=raw,file=${VMDIR}/${VMNAME}-vars.fd"
else
echo " - EFI: Booting requested but no EFI firmware found."
echo " Booting from Legacy BIOS."
fi
echo " - BIOS: EFI"
else
echo " - BIOS: Legacy"
fi
echo " - Disk: ${disk_img} (${disk})"
if [ ! -f "${disk_img}" ]; then
# If there is no disk image, create a new image.
2020-03-20 15:31:24 +00:00
${QEMU_IMG} create -q -f qcow2 "${disk_img}" "${disk}"
echo " Just created, booting from ${iso}"
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-20 15:31:24 +00:00
elif [ -e ${disk_img} ]; then
# Check there isn't already a process attached to the disk image.
QEMU_LOCK_TEST=$(${QEMU_IMG} info ${disk_img} 2>/dev/null)
if [ $? -ne 0 ]; then
echo " Failed to get "write" lock. Is another process using the disk?"
exit 1
2020-03-20 15:31:24 +00:00
else
disk_curr_size=$(stat -c%s "${disk_img}")
if [ ${disk_curr_size} -le ${disk_min_size} ]; then
echo " Looks unused, booting from ${iso}"
else
# If there is a disk image, that appears to have an install
# then do not boot from the iso
iso=""
fi
2020-03-20 15:31:24 +00:00
fi
fi
# Has the status quo been requested?
if [ "${STATUSQUO}" == "-snapshot" ] && [ -z "${iso}" ]; then
echo " Existing disk state will be preserved, no writes will be committed."
fi
local cores="1"
local allcores=$(nproc --all)
if [ ${allcores} -ge 8 ]; then
cores="4"
elif [ ${allcores} -ge 4 ]; then
cores="2"
fi
echo " - CPU: ${cores} Core(s)"
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
echo " - RAM: ${ram}"
echo " - UI: ${UI}"
echo " - VIRGL: ${VIRGL}"
local xres=1152
local yres=648
if [ "${XDG_SESSION_TYPE}" == "x11" ]; then
local LOWEST_WIDTH=$(xrandr --listmonitors | grep -v Monitors | cut -d' ' -f4 | cut -d'/' -f1 | sort | head -n1)
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
fi
echo " - Display: ${xres}x${yres}"
2020-03-20 20:35:11 +00:00
# Set the hostname of the VM
local NET="user,hostname=${VMNAME}"
# If smbd is available, export $HOME to the guest via samba
if [ -e /snap/qemu-virgil/current/usr/sbin/smbd ]; then
2020-03-20 20:35:11 +00:00
NET="${NET},smb=${HOME}"
fi
2020-03-20 20:35:11 +00:00
if [[ ${NET} == *"smb"* ]]; then
echo " - smbd: ${HOME} will be exported to the guest via smb://10.0.2.4/qemu"
else
2020-03-19 15:26:51 +00:00
echo " - smbd: ${HOME} will not be exported to the guest. 'smbd' not found."
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-15 23:13:25 +00:00
# Boot the iso image
${QEMU} -name ${VMNAME},process=${VMNAME} \
${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} \
2020-03-20 20:35:11 +00:00
-netdev ${NET},id=nic \
-device virtio-net,netdev=nic \
2020-03-15 23:13:25 +00:00
-rtc base=localtime,clock=host \
-serial mon:stdio \
-audiodev pa,id=pa,server=unix:$XDG_RUNTIME_DIR/pulse/native,out.stream-name=${LAUNCHER}-${VMNAME},in.stream-name=${LAUNCHER}-${VMNAME} \
-device intel-hda -device hda-duplex,audiodev=pa \
-device qemu-xhci,id=xhci,p2=8,p3=8 -device usb-kbd -device usb-tablet \
2020-03-15 23:13:25 +00:00
-object rng-random,id=rng0,filename=/dev/urandom \
-device virtio-rng-pci,rng=rng0 \
-device virtio-vga,virgl=${VIRGL},xres=${xres},yres=${yres} \
2020-03-20 20:37:11 +00:00
-display ${UI},gl=${GL} ${STATUSQUO} \
2020-03-19 15:28:15 +00:00
"$@"
2020-03-15 23:13:25 +00:00
}
function usage() {
echo
echo "Usage"
echo " ${LAUNCHER} --vm ubuntu.conf"
echo
echo "You can also pass optional parameters"
2020-03-20 18:22:03 +00:00
echo " --delete : Delete the disk image."
echo " --efi : Enable EFI BIOS."
echo " --snapshot apply <tag> : Apply/restore a snapshot."
echo " --snapshot create <tag> : Create a snapshot."
echo " --snapshot delete <tag> : Delete a snapshot."
echo " --snapshot info : Show disk/snapshot info."
echo " --status-quo : Do not commit any changes to disk/snapshot."
2020-03-15 23:13:25 +00:00
exit 1
}
DELETE=0
2020-03-19 01:41:58 +00:00
ENABLE_EFI=0
readonly QEMU="/snap/bin/qemu-virgil"
readonly QEMU_IMG="/snap/bin/qemu-virgil.qemu-img"
readonly LAUNCHER=$(basename $0)
2020-03-20 18:17:53 +00:00
SNAPSHOT_ACTION=""
SNAPSHOT_TAG=""
STATUSQUO=""
2020-03-15 23:13:25 +00:00
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;;
-snapshot|--snapshot)
2020-03-20 18:17:53 +00:00
SNAPSHOT_ACTION="${2}"
if [ -z "${SNAPSHOT_ACTION}" ]; then
echo "ERROR! No snapshot action provided."
exit 1
fi
shift
SNAPSHOT_TAG="${2}"
if [ -z "${SNAPSHOT_TAG}" ] && [ "${SNAPSHOT_ACTION}" != "info" ]; then
echo "ERROR! No snapshot tag provided."
exit 1
fi
shift
2020-03-15 23:13:25 +00:00
shift;;
-status-quo|--status-quo)
STATUSQUO="-snapshot"
shift;;
2020-03-15 23:13:25 +00:00
-vm|--vm)
VM="$2"
shift
shift;;
-h|--h|-help|--help)
usage;;
*)
echo "ERROR! \"${1}\" is not a supported parameter."
usage;;
esac
done
# Check we have qemu-virgil available
if [ ! -e "${QEMU}" ] && [ ! -e "${QEMU_IMG}" ]; then
echo "ERROR! qemu-virgil not found. Please install the qemu-virgil snap."
echo " https://snapcraft.io/qemu-virgil"
exit 1
fi
if [ -n "${VM}" ] || [ -e "${VM}" ]; then
source "${VM}"
2020-03-20 18:16:08 +00:00
if [ -z "${disk_img}" ]; then
echo "ERROR! No disk_img defined."
exit 1
fi
else
echo "ERROR! Virtual machine configuration not found."
usage
2020-03-15 23:13:25 +00:00
fi
if [ ${DELETE} -eq 1 ]; then
disk_delete
2020-03-20 18:17:53 +00:00
exit
2020-03-15 23:13:25 +00:00
fi
2020-03-20 18:17:53 +00:00
if [ -n "${SNAPSHOT_ACTION}" ]; then
case ${SNAPSHOT_ACTION} in
apply)
snapshot_apply "${SNAPSHOT_TAG}"
snapshot_info
exit;;
create)
snapshot_create "${SNAPSHOT_TAG}"
snapshot_info
exit;;
delete)
snapshot_delete "${SNAPSHOT_TAG}"
snapshot_info
exit;;
info)
snapshot_info
exit;;
*)
echo "ERROR! \"${SNAPSHOT_ACTION}\" is not a supported snapshot action."
usage;;
esac
2020-03-15 23:13:25 +00:00
fi
2020-03-19 23:20:58 +00:00
vm_boot