Skip to content

Instantly share code, notes, and snippets.

@TilBlechschmidt
Last active May 14, 2016 16:16
Show Gist options
  • Save TilBlechschmidt/00c2d20fe3c66f75867662686e689d9d to your computer and use it in GitHub Desktop.
Save TilBlechschmidt/00c2d20fe3c66f75867662686e689d9d to your computer and use it in GitHub Desktop.
QEMU wrapper scripts
.
├── cd_images
│   └── virtio.iso
├── OVMF
│   ├── OVMF_CODE-pure-efi.fd
│   └── OVMF_VARS-pure-efi-untouched.fd
├── qemu_manager.py
├── qemu_manager.sh
└── VM
└── windows_base_uefi
├── OVMF_VARS-pure-efi-win7.fd
├── vm.json
└── win7_hp_uefi_enUS_clean_unregistered.qcow2
5 directories, 11 files
#!/usr/bin/python3.5
from __future__ import print_function
from pprint import pprint
from os import path
import sys
import json
import psutil
OVMF_CODE_PATH = path.abspath("./OVMF/OVMF_CODE-pure-efi.fd")
def called_by_qmsh():
me = psutil.Process()
parent = psutil.Process(me.ppid())
grandparent = psutil.Process(parent.ppid())
called_from_qm = False
for arg in grandparent.cmdline():
if "qemu_manager.sh" in arg:
called_from_qm = True
return called_from_qm
def eprint(*args, **kwargs):
args = (" \033[93m*\033[39m",) + args
print(*args, file=sys.stderr, **kwargs)
def parse_vm(name):
vm_path = path.join(path.abspath("./VM"), name)
with open(path.join(vm_path, 'vm.json')) as data_file:
vm_config = json.load(data_file)
vm_config["vm_path"] = vm_path
return vm_config
def start_vm(vm_path=None, kvm=True, uefi=None, virtio=True,
mem=4086, cores=4, cpu="host", cpu_args=None,
vga=None, sound=None,
hdd=None, ide=None, scsi=None):
if vm_path is None:
exit("ERROR: No VM path passed")
if hdd is None:
hdd = []
if ide is None:
ide = []
if scsi is None:
scsi = []
additional_options = "-nodefaults -nodefconfig -net nic,model=virtio -net vde"
cmdline = "qemu-system-x86_64 "
drive_id = 0
# Enable KVM
cmdline += "-enable-kvm " if kvm else ""
# ------- Base hardware -------
# Set the RAM allocation
cmdline += "-m " + str(mem) + " "
# Set the CPU options
cmdline += "-cpu " + (cpu + "," + cpu_args if cpu_args else cpu) + " "
# Set the CPU core/socket counts
cmdline += "-smp " + str(cores) + ",sockets=1,cores=" + str(cores) + ",threads=1 "
# Enable UEFI
if uefi:
uefi = path.join(vm_path, uefi)
cmdline += "-drive if=pflash,format=raw,readonly,file=" + OVMF_CODE_PATH + " "
cmdline += "-drive if=pflash,format=raw,file=" + uefi + " "
# cmdline += "-debugcon file:debug.log -global isa-debugcon.iobase=0x402 "
cmdline += "-spice port=5930,disable-ticketing "
cmdline += "-device virtio-serial "
cmdline += "-chardev spicevmc,id=vdagent,name=vdagent "
cmdline += "-device virtserialport,chardev=vdagent,name=com.redhat.spice.0 "
vga = "qxl"
eprint("WARNING: Overridden VGA with qxl since UEFI (and therefore the spice server) is enabled!")
# Set the VGA emulation
cmdline += "-vga " + (str(vga) + " -usb -usbdevice tablet" if vga else "none") + " "
# Set the sound device
if sound:
cmdline += "-soundhw " + str(sound) + " "
# ------- Drives -------
def add_drive(file, d_id, opt=""):
return "-drive file=" + file + ",id=drive_" + str(d_id) + ",if=none" + ("," + opt + " " if opt != "" else " ")
if virtio:
cmdline += "-device virtio-scsi-pci,id=scsi "
# IDE
for dvd_image in ide:
dvd_image = dvd_image.replace("GLOBAL/", path.abspath("./cd_images") + "/", 1)
cmdline += add_drive(dvd_image, drive_id) + "-device ide-cd,bus=ide." + str(drive_id) + ",drive=drive_"\
+ str(drive_id) + " "
drive_id += 1
# SCSI
for dvd_image in scsi:
dvd_image = dvd_image.replace("GLOBAL/", path.abspath("./cd_images") + "/", 1)
cmdline += add_drive(dvd_image, drive_id) + "-device scsi-cd,drive=drive_" + str(drive_id) + " "
drive_id += 1
# HDD
for (hdd_file, options) in hdd:
hdd_file = path.join(vm_path, hdd_file)
cmdline += add_drive(hdd_file, drive_id, options) + "-device scsi-hd,drive=drive_" + str(drive_id) + " "
drive_id += 1
# TODO: Set up VFIO binding
# print("echo 1 > /sys/module/kvm/parameters/ignore_msrs")
print(cmdline + additional_options)
# -rtc base=localtime \
# -net user,smb=/home/themegatb/ \
# -net nic,model=virtio
def main():
if not called_by_qmsh():
eprint("This script shouldn't be called directly.")
exit(1)
vm_config = parse_vm(sys.argv[1])
vm_config.pop("name", None) # eprint("Loaded " + vm_config.pop("name"))
start_vm(**vm_config)
if __name__ == '__main__':
main()
#!/usr/bin/env bash
# TODO: Argument parsing and quiet flag for qemu
if [ "$EUID" -ne 0 ]; then
echo -e " \e[91m*\e[39m Please run as root"
exit
fi
if [ -z "$1" ]; then
echo -e " \e[91m*\e[39m Please provide a VM name"
exit
else
VM=$1
fi
SPICE=0
if [ ! -z "$2" ] && [ "$2" == "--spice" ] || [ "$2" == "-s" ]; then
SPICE=1
fi
cols=$(tput cols)
function move_before_end_of_line {
tput el
for ((n=0;n<$1;n++)); do
tput cub1
done
}
function begin {
echo -e " \e[92m*\e[39m $1 ..."
}
function end {
move_before_end_of_line 8
if [ $1 -eq 0 ]; then
echo -e " \e[1;96m[\e[92m ok \e[96m]\e[39m\e[21m "
else
echo -e " \e[1m\e[96m[\e[91m !! \e[96m]\e[39m\e[21m"
fi
}
function try {
"$@"
local status=$?
if [ ${status} -ne 0 ]; then
# echo "error with $1" >&2
end ${status}
exit ${status}
fi
return ${status}
}
begin "Exporting PulseAudio driver"
try export QEMU_PA_SAMPLES=128
try export QEMU_AUDIO_DRV="pa"
end $?
begin "Setting up IP forwarding"
vde_switch -tap tap0 -mod 660 -group kvm >/dev/null 2>&1 &
TAP_PID=$!
while ! ip a | grep -F "tap0" > /dev/null; do
sleep 0.5
done
try ip addr add 10.0.2.1/24 dev tap0
try ip link set dev tap0 up
try sysctl -w net.ipv4.ip_forward=1 > /dev/null
try iptables -t nat -A POSTROUTING -s 10.0.2.0/24 -j MASQUERADE
end $?
if [ ${SPICE} -eq 1 ]; then
begin "Launching spice"
try sh -c "(sleep 0.5 && i3-msg 'workspace '8: '; exec spicy -f -h 127.0.0.1 -p 5930')" > /dev/null &
end $?
fi
begin "Starting VM"
cmd=$(./qemu_manager.py ${VM})
#echo ${cmd}
echo -e "\e[90m"
try ${cmd}
end $?
begin "Removing IP forwarding device"
ip link delete tap0
kill ${TAP_PID}
end $?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment