commit 7fdbc06ca4f59d3390513a66709df9ec605cb2e0 Author: mykola2312 <49044616+mykola2312@users.noreply.github.com> Date: Mon Dec 2 03:25:37 2024 +0200 initial commit diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..038d105 --- /dev/null +++ b/LICENSE @@ -0,0 +1,25 @@ +BSD 2-Clause License + +Copyright (c) 2024, mykola2312. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8e4092c --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# kuemu + +Bash declarative QEMU tool + +## Documentation + +### Config +```KUEMU_DISK_PATH``` - set this to your appropriate location of virtual machine images. + +```QEMU_BIOS_ROM```, ```QEMU_UEFI_ROM```, ```QEMU_UEFI_NVRAM``` - ensure they exist in your filesystem. If not, install required packages and firmware, for example for UEFI ROMs You need OVMF EDK2. + +### Syntax + +```name "name of virtual machine``` - set the name of VM. This also will be used in calculation of disk path + +```arch "arch-suffix``` - will be translated into qemu-system-, like ```qemu-system-x86_64``` + +```machine "machine"``` - QEMU uses machine presets, that populates buses, devices and such. Recommended: q35 + +```cpu "cpu"``` - host, or custom cpu config + +```smp num-cores``` - refers to amount of cores + +```ram 1024m``` - same as -m parameter of QEMU. For example, 1G or 1024M are accepted. + +```vga vga-type``` - VGA device. Recommended: qxl + +```monitor``` - spawn QEMU monitor, useful for troubleshooting + +```spice``` or ```spice ``` - spawn SPICE graphics server. Connect with ```spicy``` + +```no_acpi``` - disables ACPI. Needed for running old operating systems. + +Path calculation: + +"name" translates to ```$KUEMU_DISK_PATH/name.img```, "name" "fd" - ```$KUEMU_DISK_PATH/name.fd``` + +```uefi``` - loads UEFI ROMs, populates NVRAM variables into VM images path, like ```$KUEMU_DISK_PATH/name-nvram.fd``` + +```bios``` - loads BIOS ROM. Better don't use it, since QEMU has its own defaults. + +```ide_disk "disk-name"```, ```sata_disk "name"```, ```virtio_disk "name"``` - creates IDE/SATA/Virtio disk drives, where ```name``` translates to ```$KUEMU_DISK_PATH/vm_name-name.img```. When ```name``` is empty string, it will translate just to virtual machine's name, like ```$KUEMU_DISK_PATH/vm_name.img``` + +```ide_cdrom "path"```, ```sata_cdrom "path"```, ```virtio_cdrom "path"``` - creates IDE/SATA/Virtio CDROMs, where "path" must be full path to file. + +```network "device-model" "type" "name"``` - create network device. For model, you either specify ```e1000```, when guest doesn't have virtio drivers, or ```virtio-net``` for virtio network device. Type only supports ```tap```, where name is name of the tap (that You probably want to add to bridge) + +```kuemu_start``` - finishes QEMU argument building and spawns virtual machine. + +## Examples + +### Full virtio guest +``` +#!/usr/bin/env bash + +source kuemu.sh + +name "freebsd-dev" +arch "x86_64" +machine "q35" +smp 4 +ram "4G" +vga "qxl" +monitor +spice +uefi +virtio_disk "" +network "virtio-net" "tap" "vnet0tap1" + +kuemu_start +``` + + +### Windows 7 +``` +#!/usr/bin/env bash + +source kuemu.sh + +name "win7" +arch "x86_64" +machine "q35" +smp 4 +ram "4G" +vga "qxl" +monitor +spice +uefi +sata_disk "" +network "e1000" "tap" "vnet0tap1" + +kuemu_start +``` \ No newline at end of file diff --git a/kuemu.sh b/kuemu.sh new file mode 100644 index 0000000..50acbf6 --- /dev/null +++ b/kuemu.sh @@ -0,0 +1,225 @@ +KUEMU_DISK_PATH="/drive/virtual-machines" + +QEMU_BIOS_ROM="/usr/share/qemu/bios-microvm.bin" +QEMU_UEFI_ROM="/usr/share/OVMF/OVMF_CODE.fd" +QEMU_UEFI_NVRAM="/usr/share/OVMF/OVMF_VARS.fd" +QEMU_ACCEL="kvm" + +QEMU_MODEL_IDE_BUS="piix3-ide" +QEMU_MODEL_AHCI_BUS="ahci" + +vm_name="" +cmdline_file=$(mktemp) + +model_ide_bus="$QEMU_MODEL_IDE_BUS" +model_ahci_bus="$QEMU_MODEL_AHCI_BUS" + +function append() { + printf "%s " "$1" >> "$cmdline_file" +} + +function counter_create() { + counter=$(mktemp) + echo "$1" > "$counter" + echo "$counter" +} + +function counter_read() { + cat "$1" +} + +function counter_increment() { + echo $(( $(cat "$1") + 1 )) > "$1" +} + +function counter_decrement() { + echo $(( $(cat "$1") - 1 )) > "$1" +} + +function counter_delete() { + rm "$1" +} + +function path_disk() { + # + # disk_name + # disk_name, ext + if [ ! -z "$2" ]; then + echo "$KUEMU_DISK_PATH/$vm_name-$1.$2" + elif [ ! -z "$1" ]; then + echo "$KUEMU_DISK_PATH/$vm_name-$1.img" + else + echo "$KUEMU_DISK_PATH/$vm_name.img" + fi +} + +function name() { + vm_name="$1" +} + +function arch() { + append "qemu-system-$1" +} + +function machine() { + append "-machine type=$1,accel=$QEMU_ACCEL" +} + +function cpu() { + if [ ! -z "$1" ]; then + append "-cpu $1" + else + append "-cpu host" + fi +} + +function smp() { + append "-smp $1" +} + +function ram() { + append "-m $1" +} + +function vga() { + append "-vga $1" +} + +function monitor() { + append "-monitor stdio" +} + +function spice() { + # port + if [ ! -z "$1" ]; then + append "-spice port=$1,disable-ticketing=on" + else + append "-spice port=5924,disable-ticketing=on" + fi +} + +function no_acpi() { + append "-no-acpi" +} + +function uefi() { + append "-drive if=pflash,format=raw,file=$QEMU_UEFI_ROM" + nvram=$(path_disk "nvram" "fd") + if [ ! -f "$nvram" ]; then + # create nvram + cp "$QEMU_UEFI_NVRAM" "$nvram" + fi + append "-drive if=pflash,format=raw,file=$nvram" +} + +function bios() { + append "-bios $QEMU_BIOS_ROM" +} + +function boot() { + append "-boot $1" +} + +bus_ide="ide" +bus_ide_counter=$(counter_create 0) + +drive_counter=$(counter_create 0) + +function _ide_disk() { + # disk type, type, path + unit=$(counter_read $bus_ide_counter) + counter_increment $bus_ide_counter + + drive="drive-$(counter_read $drive_counter)" + counter_increment $drive_counter + + append "-drive id=$drive,format=raw,media=$2,file=$3,if=none" + append "-device $1,drive=$drive,bus=$bus_ide.$unit" +} + +function ide_disk() { + # name + _ide_disk "ide-hd" "disk" $(path_disk "$1") +} + +function ide_cdrom() { + # path + _ide_disk "ide-cd" "cdrom" "$1" +} + +bus_ahci="" +bus_ahci_counter=$(counter_create 0) + +function _sata_disk() { + # disk type, media type, path + if [ -z "$bus_ahci" ]; then + append "-device $model_ahci_bus,id=ahci" + bus_ahci="ahci" + fi + unit=$(counter_read $bus_ide_counter) + counter_increment $bus_ahci_counter + + drive="drive-$(counter_read $drive_counter)" + counter_increment $drive_counter + + append "-drive id=$drive,format=raw,media=$2,file=$3,if=none" + append "-device $1,drive=$drive,bus=$bus_ahci.$unit" +} + +function sata_disk() { + # name + _sata_disk "ide-hd" "disk" $(path_disk "$1") +} + +function sata_cdrom() { + # path + _sata_disk "ide-cd" "cdrom" "$1" +} + +function _virtio_disk() { + # scsi type, media type, path + drive="drive-$(counter_read $drive_counter)" + counter_increment $drive_counter + + append "-drive id=$drive,format=raw,media=$2,file=$3,if=virtio" +} + +function virtio_disk() { + # name + _virtio_disk "scsi-hd" "disk" $(path_disk "$1") +} + +function virtio_cdrom() { + # path + _virtio_disk "scsi-cd" "cdrom" "$1" +} + +nic_counter=$(counter_create 0) +function network() { + # model, mode (tap or bridge), tap name / bridge + nic="nic$(counter_read $nic_counter)" + counter_increment $nic_counter + + append "-device $1,netdev=$nic" + case "$2" in + "tap") + append "-netdev tap,id=$nic,ifname=$3,script=no,downscript=no" + ;; + *) + echo "unknown network type $2" + exit 1 + ;; + esac +} + +function kuemu_start() { + append "-name $vm_name" + # cleanup counters + counter_delete $bus_ide_counter + counter_delete $drive_counter + counter_delete $bus_ahci_counter + counter_delete $nic_counter + # execute qemu command + bash $cmdline_file +} +