Initial commit
This commit is contained in:
commit
9ed17eca06
13 changed files with 929 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
/target
|
297
Cargo.lock
generated
Normal file
297
Cargo.lock
generated
Normal file
|
@ -0,0 +1,297 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
[[package]]
|
||||
name = "aho-corasick"
|
||||
version = "0.7.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.40"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b"
|
||||
|
||||
[[package]]
|
||||
name = "arrayvec"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.0.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "config"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b1b9d958c2b1368a663f05538fc1b5975adce1e19f435acceae987aceeeb369"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"nom",
|
||||
"rust-ini",
|
||||
"serde 1.0.125",
|
||||
"serde-hjson",
|
||||
"serde_json",
|
||||
"toml",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "0.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||
|
||||
[[package]]
|
||||
name = "kiam"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fec32b07a91b3ac2bca298af854b84860969f099811888fe0d9edf7bee95ce2"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "lexical-core"
|
||||
version = "0.7.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "21f866863575d0e1d654fbeeabdc927292fdf862873dc3c96c6f753357e13374"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"ryu",
|
||||
"static_assertions",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3"
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.3.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "5.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af"
|
||||
dependencies = [
|
||||
"lexical-core",
|
||||
"memchr",
|
||||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.1.43"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31"
|
||||
dependencies = [
|
||||
"num-traits 0.2.14",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
|
||||
dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
|
||||
dependencies = [
|
||||
"aho-corasick",
|
||||
"memchr",
|
||||
"regex-syntax",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex-syntax"
|
||||
version = "0.6.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
|
||||
|
||||
[[package]]
|
||||
name = "rust-ini"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e52c148ef37f8c375d49d5a73aa70713125b7f19095948a923f80afdeb22ec2"
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "0.8.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde-hjson"
|
||||
version = "0.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a3a4e0ea8a88553209f6cc6cfe8724ecad22e1acf372793c27d995290fe74f8"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"num-traits 0.1.43",
|
||||
"regex",
|
||||
"serde 0.8.23",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.125"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.64"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"ryu",
|
||||
"serde 1.0.125",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "static_assertions"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "1.0.69"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
|
||||
dependencies = [
|
||||
"serde 1.0.125",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe"
|
||||
|
||||
[[package]]
|
||||
name = "vore"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"vore-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vore-core"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"config",
|
||||
"kiam",
|
||||
"serde 1.0.125",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vored"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"vore-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
2
Cargo.toml
Normal file
2
Cargo.toml
Normal file
|
@ -0,0 +1,2 @@
|
|||
[workspace]
|
||||
members = ["vored", "vore", "vore-core"]
|
21
config/example.toml
Normal file
21
config/example.toml
Normal file
|
@ -0,0 +1,21 @@
|
|||
[machine]
|
||||
name = "win10"
|
||||
memory = "12G"
|
||||
|
||||
[cpu]
|
||||
amount = 12
|
||||
|
||||
[[disk]]
|
||||
path = "/dev/disk/by-id/wwn-0x500a0751f008e09d"
|
||||
|
||||
[[disk]]
|
||||
path = "/dev/disk/by-id/wwn-0x5002538e4038852d"
|
||||
|
||||
[uefi]
|
||||
enabled = true
|
||||
|
||||
[scream]
|
||||
enabled = true
|
||||
|
||||
[looking-glass]
|
||||
enabled = true
|
146
resources/qemu-cmdline.txt
Normal file
146
resources/qemu-cmdline.txt
Normal file
|
@ -0,0 +1,146 @@
|
|||
/bin/qemu-system-x86_64
|
||||
-name
|
||||
guest=win10,debug-threads=on
|
||||
-S
|
||||
-object
|
||||
secret,id=masterKey0,format=raw,file=/var/lib/libvirt/qemu/domain-1-win10/master-key.aes
|
||||
-blockdev
|
||||
{"driver":"file","filename":"/usr/share/OVMF/OVMF_CODE.fd","node-name":"libvirt-pflash0-storage","auto-read-only":true,"discard":"unmap"}
|
||||
-blockdev
|
||||
{"node-name":"libvirt-pflash0-format","read-only":true,"driver":"raw","file":"libvirt-pflash0-storage"}
|
||||
-blockdev
|
||||
{"driver":"file","filename":"/usr/share/OVMF/OVMF_VARS.fd","node-name":"libvirt-pflash1-storage","auto-read-only":true,"discard":"unmap"}
|
||||
-blockdev
|
||||
{"node-name":"libvirt-pflash1-format","read-only":false,"driver":"raw","file":"libvirt-pflash1-storage"}
|
||||
-machine
|
||||
pc-q35-3.0,accel=kvm,usb=off,vmport=off,dump-guest-core=off,kernel_irqchip=on,pflash0=libvirt-pflash0-format,pflash1=libvirt-pflash1-format,memory-backend=pc.ram
|
||||
-cpu
|
||||
host,migratable=on,hv-time,hv-relaxed,hv-vapic,hv-spinlocks=0x1fff,hv-vendor-id=whatever,kvm=off
|
||||
-m
|
||||
16384
|
||||
-object
|
||||
memory-backend-ram,id=pc.ram,size=17179869184
|
||||
-overcommit
|
||||
mem-lock=off
|
||||
-smp
|
||||
12,sockets=1,dies=1,cores=6,threads=2
|
||||
-object
|
||||
iothread,id=iothread1
|
||||
-uuid
|
||||
29d2307c-ee76-4471-85f1-ee758121a99b
|
||||
-no-user-config
|
||||
-nodefaults
|
||||
-chardev
|
||||
socket,id=charmonitor,fd=29,server=on,wait=off
|
||||
-mon
|
||||
chardev=charmonitor,id=monitor,mode=control
|
||||
-rtc
|
||||
base=localtime,driftfix=slew
|
||||
-global
|
||||
kvm-pit.lost_tick_policy=delay
|
||||
-no-hpet
|
||||
-no-shutdown
|
||||
-global
|
||||
ICH9-LPC.disable_s3=1
|
||||
-global
|
||||
ICH9-LPC.disable_s4=1
|
||||
-boot
|
||||
strict=on
|
||||
-device
|
||||
i82801b11-bridge,id=pci.1,bus=pcie.0,addr=0x1e
|
||||
-device
|
||||
pci-bridge,chassis_nr=2,id=pci.2,bus=pci.1,addr=0x0
|
||||
-device
|
||||
pcie-root-port,port=0x10,chassis=3,id=pci.3,bus=pcie.0,multifunction=on,addr=0x2
|
||||
-device
|
||||
pcie-root-port,port=0x11,chassis=4,id=pci.4,bus=pcie.0,addr=0x2.0x1
|
||||
-device
|
||||
pcie-root-port,port=0x12,chassis=5,id=pci.5,bus=pcie.0,addr=0x2.0x2
|
||||
-device
|
||||
pcie-root-port,port=0x13,chassis=6,id=pci.6,bus=pcie.0,addr=0x2.0x3
|
||||
-device
|
||||
pcie-root-port,port=0x14,chassis=7,id=pci.7,bus=pcie.0,addr=0x2.0x4
|
||||
-device
|
||||
pcie-root-port,port=0x15,chassis=8,id=pci.8,bus=pcie.0,addr=0x2.0x5
|
||||
-device
|
||||
pcie-root-port,port=0x16,chassis=9,id=pci.9,bus=pcie.0,addr=0x2.0x6
|
||||
-device
|
||||
pcie-root-port,port=0x17,chassis=10,id=pci.10,bus=pcie.0,addr=0x2.0x7
|
||||
-device
|
||||
pcie-root-port,port=0x18,chassis=11,id=pci.11,bus=pcie.0,multifunction=on,addr=0x3
|
||||
-device
|
||||
pcie-root-port,port=0x19,chassis=12,id=pci.12,bus=pcie.0,addr=0x3.0x1
|
||||
-device
|
||||
pcie-root-port,port=0x1a,chassis=13,id=pci.13,bus=pcie.0,addr=0x3.0x2
|
||||
-device
|
||||
pcie-root-port,port=0x1b,chassis=14,id=pci.14,bus=pcie.0,addr=0x3.0x3
|
||||
-device
|
||||
nec-usb-xhci,id=usb,bus=pci.3,addr=0x0
|
||||
-device
|
||||
virtio-scsi-pci,id=scsi0,bus=pci.9,addr=0x0
|
||||
-device
|
||||
virtio-serial-pci,id=virtio-serial0,bus=pci.4,addr=0x0
|
||||
-blockdev
|
||||
{"driver":"host_device","filename":"/dev/disk/by-id/wwn-0x500a0751f008e09d","aio":"threads","node-name":"libvirt-2-storage","cache":{"direct":false,"no-flush":false},"auto-read-only":true,"discard":"unmap"}
|
||||
-blockdev
|
||||
{"node-name":"libvirt-2-format","read-only":false,"discard":"unmap","cache":{"direct":false,"no-flush":false},"driver":"raw","file":"libvirt-2-storage"}
|
||||
-device
|
||||
scsi-hd,bus=scsi0.0,channel=0,scsi-id=0,lun=3,device_id=drive-scsi0-0-0-3,drive=libvirt-2-format,id=scsi0-0-0-3,bootindex=1,write-cache=on
|
||||
-blockdev
|
||||
{"driver":"host_device","filename":"/dev/disk/by-id/wwn-0x5002538e4038852d","aio":"threads","node-name":"libvirt-1-storage","cache":{"direct":false,"no-flush":false},"auto-read-only":true,"discard":"unmap"}
|
||||
-blockdev
|
||||
{"node-name":"libvirt-1-format","read-only":false,"discard":"unmap","cache":{"direct":false,"no-flush":false},"driver":"raw","file":"libvirt-1-storage"}
|
||||
-device
|
||||
virtio-blk-pci,bus=pci.11,addr=0x0,drive=libvirt-1-format,id=virtio-disk4,write-cache=on
|
||||
-netdev
|
||||
tap,fd=31,id=hostnet0,vhost=on,vhostfd=32
|
||||
-device
|
||||
virtio-net-pci,netdev=hostnet0,id=net0,mac=52:54:00:9e:48:64,bus=pci.8,addr=0x0
|
||||
-netdev
|
||||
tap,fd=33,id=hostnet1,vhost=on,vhostfd=34
|
||||
-device
|
||||
virtio-net-pci,netdev=hostnet1,id=net1,mac=52:54:00:fa:57:7d,bus=pci.10,addr=0x0
|
||||
-chardev
|
||||
pty,id=charserial0
|
||||
-device
|
||||
isa-serial,chardev=charserial0,id=serial0
|
||||
-chardev
|
||||
spicevmc,id=charchannel0,name=vdagent
|
||||
-device
|
||||
virtserialport,bus=virtio-serial0.0,nr=1,chardev=charchannel0,id=channel0,name=com.redhat.spice.0
|
||||
-device
|
||||
virtio-mouse-pci,id=input0,bus=pci.13,addr=0x0
|
||||
-audiodev
|
||||
id=audio1,driver=spice
|
||||
-spice
|
||||
unix,addr=/tmp/win.sock,disable-ticketing=on,seamless-migration=on
|
||||
-device
|
||||
cirrus-vga,id=video0,bus=pcie.0,addr=0x1
|
||||
-device
|
||||
ich9-intel-hda,id=sound0,bus=pcie.0,addr=0x1b
|
||||
-device
|
||||
hda-duplex,id=sound0-codec0,bus=sound0.0,cad=0,audiodev=audio1
|
||||
-device
|
||||
vfio-pci,host=0000:08:00.0,id=hostdev0,bus=pci.6,addr=0x0
|
||||
-device
|
||||
vfio-pci,host=0000:08:00.1,id=hostdev1,bus=pci.7,addr=0x0
|
||||
-device
|
||||
vfio-pci,host=0000:0a:00.3,id=hostdev2,bus=pci.14,addr=0x0
|
||||
-device
|
||||
virtio-balloon-pci,id=balloon0,bus=pci.5,addr=0x0
|
||||
-device
|
||||
usb-kbd
|
||||
-audiodev
|
||||
pa,id=win10,server=/run/user/1000/pulse/native
|
||||
-sandbox
|
||||
on,obsolete=deny,elevateprivileges=deny,spawn=deny,resourcecontrol=deny
|
||||
-object
|
||||
memory-backend-file,id=shmmem-shmem0,mem-path=/dev/shm/looking-glass,size=67108864,share=on
|
||||
-device
|
||||
ivshmem-plain,id=shmem0,memdev=shmmem-shmem0,bus=pci.2,addr=0x1
|
||||
-object
|
||||
memory-backend-file,id=shmmem-shmem1,mem-path=/dev/shm/scream,size=2097152,share=on
|
||||
-device
|
||||
ivshmem-plain,id=shmem1,memdev=shmmem-shmem1,bus=pci.2,addr=0x2
|
||||
-msg
|
||||
timestamp=on
|
13
vore-core/Cargo.toml
Normal file
13
vore-core/Cargo.toml
Normal file
|
@ -0,0 +1,13 @@
|
|||
[package]
|
||||
name = "vore-core"
|
||||
version = "0.1.0"
|
||||
authors = ["eater <=@eater.me>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
config = "0.11.0"
|
||||
serde = { version = "1.0.125", features = ["serde_derive"] }
|
||||
anyhow = "1.0.40"
|
||||
kiam = "0.1"
|
269
vore-core/src/instance_config.rs
Normal file
269
vore-core/src/instance_config.rs
Normal file
|
@ -0,0 +1,269 @@
|
|||
use anyhow::{Context, Error};
|
||||
use config::{Config, File, FileFormat, Value};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct InstanceConfig {
|
||||
pub name: String,
|
||||
pub kvm: bool,
|
||||
pub memory: u64,
|
||||
pub cpu: CpuConfig,
|
||||
pub disks: Vec<DiskConfig>,
|
||||
pub uefi: UefiConfig,
|
||||
pub looking_glass: LookingGlassConfig,
|
||||
pub scream: ScreamConfig,
|
||||
}
|
||||
|
||||
impl InstanceConfig {
|
||||
pub fn from_toml(toml: &str) -> Result<Self, anyhow::Error> {
|
||||
let toml = Config::new().with_merged(File::from_str(toml, FileFormat::Toml))?;
|
||||
Self::from_config(toml)
|
||||
}
|
||||
|
||||
pub fn from_config(config: Config) -> Result<InstanceConfig, anyhow::Error> {
|
||||
let mut instance_config = InstanceConfig::default();
|
||||
if let Ok(name) = config.get_str("machine.name") {
|
||||
instance_config.name = name
|
||||
}
|
||||
|
||||
if let Ok(kvm) = config.get::<Value>("machine.kvm") {
|
||||
instance_config.kvm = kvm.into_bool().context("machine.kvm should be a boolean")?;
|
||||
}
|
||||
|
||||
if let Ok(mem) = config.get::<Value>("machine.memory") {
|
||||
let mem = mem
|
||||
.into_str()
|
||||
.context("machine.memory should be a string or number")?;
|
||||
instance_config.memory = parse_size(&mem)?;
|
||||
}
|
||||
|
||||
if let Ok(cpu) = config.get_table("cpu") {
|
||||
instance_config.cpu.apply_table(cpu)?
|
||||
}
|
||||
|
||||
if let Ok(disks) = config.get::<Value>("disk") {
|
||||
let arr = disks.into_array().context("disk should be an array")?;
|
||||
for (i, disk) in arr.into_iter().enumerate() {
|
||||
let table = disk
|
||||
.into_table()
|
||||
.with_context(|| format!("disk[{}] should be a table", i))?;
|
||||
instance_config.disks.push(DiskConfig::from_table(table)?);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(instance_config)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for InstanceConfig {
|
||||
fn default() -> Self {
|
||||
InstanceConfig {
|
||||
name: "vore".to_string(),
|
||||
kvm: true,
|
||||
// 2 GB
|
||||
memory: 2 * 1024 * 1024 * 1024,
|
||||
cpu: Default::default(),
|
||||
disks: vec![],
|
||||
uefi: Default::default(),
|
||||
looking_glass: Default::default(),
|
||||
scream: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct CpuConfig {
|
||||
pub amount: u64,
|
||||
pub cores: u64,
|
||||
pub threads: u64,
|
||||
pub dies: u64,
|
||||
pub sockets: u64,
|
||||
}
|
||||
|
||||
impl Default for CpuConfig {
|
||||
fn default() -> Self {
|
||||
CpuConfig {
|
||||
amount: 2,
|
||||
cores: 1,
|
||||
threads: 2,
|
||||
dies: 1,
|
||||
sockets: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn get_positive_number_from_table(
|
||||
table: &HashMap<String, Value>,
|
||||
key: &str,
|
||||
prefix: &str,
|
||||
) -> Result<Option<u64>, Error> {
|
||||
table
|
||||
.get(key)
|
||||
.cloned()
|
||||
.map(|x| {
|
||||
x.into_int()
|
||||
.with_context(|| format!("Failed to parse {}.{} as number", prefix, key))
|
||||
.and_then(|x| {
|
||||
Some(x)
|
||||
.filter(|x| !x.is_negative())
|
||||
.map(|x| x as u64)
|
||||
.ok_or_else(|| {
|
||||
anyhow::Error::msg(format!("{}.{} can't be negative", prefix, key))
|
||||
})
|
||||
})
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
impl CpuConfig {
|
||||
fn apply_table(&mut self, table: HashMap<String, Value>) -> Result<(), anyhow::Error> {
|
||||
if let Some(amount) = get_positive_number_from_table(&table, "amount", "cpu")? {
|
||||
self.amount = amount;
|
||||
}
|
||||
|
||||
if let Some(cores) = get_positive_number_from_table(&table, "cores", "cpu")? {
|
||||
self.cores = cores;
|
||||
}
|
||||
|
||||
if let Some(threads) = get_positive_number_from_table(&table, "threads", "cpu")? {
|
||||
self.threads = threads;
|
||||
}
|
||||
|
||||
if let Some(dies) = get_positive_number_from_table(&table, "dies", "cpu")? {
|
||||
self.dies = dies;
|
||||
}
|
||||
|
||||
if let Some(sockets) = get_positive_number_from_table(&table, "sockets", "cpu")? {
|
||||
self.sockets = sockets;
|
||||
}
|
||||
|
||||
if !table.contains_key("amount") {
|
||||
self.amount = self.sockets * self.dies * self.cores * self.threads;
|
||||
} else {
|
||||
if table
|
||||
.keys()
|
||||
.any(|x| ["cores", "sockets", "dies", "threads"].contains(&x.as_str()))
|
||||
{
|
||||
let calc_amount = self.sockets * self.dies * self.cores * self.threads;
|
||||
if self.amount != calc_amount {
|
||||
Err(anyhow::Error::msg(format!("Amount of cpu's ({}) from sockets ({}), dies ({}), cores ({}) and threads ({}) differs from specified ({}) cpu's", calc_amount, self.sockets, self.dies, self.cores, self.threads, self.amount)))?;
|
||||
}
|
||||
} else {
|
||||
if (self.amount % 2) == 0 {
|
||||
self.cores = self.amount / 2;
|
||||
} else {
|
||||
self.threads = 1;
|
||||
self.cores = self.amount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_size(orig_input: &str) -> Result<u64, anyhow::Error> {
|
||||
let input = orig_input.to_string().to_lowercase().replace(" ", "");
|
||||
let mut input = input.strip_suffix("b").unwrap_or(&input);
|
||||
let mut modifier: u64 = 1;
|
||||
|
||||
if input.chars().last().unwrap_or('_').is_alphabetic() {
|
||||
modifier = match input.chars().last().unwrap() {
|
||||
'k' => {
|
||||
return Err(anyhow::Error::msg(
|
||||
"size can only be specified in megabytes or larger",
|
||||
));
|
||||
}
|
||||
'm' => 1,
|
||||
'g' => 1024,
|
||||
't' => 1024 * 1024,
|
||||
_ => {
|
||||
return Err(anyhow::Error::msg(format!(
|
||||
"'{}' is not a valid size",
|
||||
orig_input
|
||||
)));
|
||||
}
|
||||
};
|
||||
|
||||
input = &input[..input.len() - 1];
|
||||
}
|
||||
|
||||
if input.len() == 0 {
|
||||
return Err(anyhow::Error::msg(format!(
|
||||
"'{}' is not a valid size",
|
||||
orig_input
|
||||
)));
|
||||
}
|
||||
|
||||
u64::from_str(input)
|
||||
.context(format!("'{}' is not a valid size", orig_input))
|
||||
.map(|x| x * modifier)
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct UefiConfig {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for UefiConfig {
|
||||
fn default() -> Self {
|
||||
UefiConfig { enabled: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct ScreamConfig {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for ScreamConfig {
|
||||
fn default() -> Self {
|
||||
ScreamConfig { enabled: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct LookingGlassConfig {
|
||||
pub enabled: bool,
|
||||
}
|
||||
|
||||
impl Default for LookingGlassConfig {
|
||||
fn default() -> Self {
|
||||
LookingGlassConfig { enabled: false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deserialize, Serialize, Clone, Debug)]
|
||||
pub struct DiskConfig {
|
||||
pub disk_type: String,
|
||||
pub path: String,
|
||||
}
|
||||
|
||||
impl DiskConfig {
|
||||
pub fn from_table(table: HashMap<String, Value>) -> Result<DiskConfig, anyhow::Error> {
|
||||
let path = table
|
||||
.get("path")
|
||||
.cloned()
|
||||
.ok_or_else(|| anyhow::Error::msg("Disk needs a path"))?
|
||||
.into_str()
|
||||
.context("Disk path must be a string")?;
|
||||
|
||||
let disk_type = if let Some(disk_type) = table.get("type").cloned() {
|
||||
disk_type.into_str()?
|
||||
} else {
|
||||
(kiam::when! {
|
||||
path.starts_with("/dev") => "raw",
|
||||
path.ends_with(".qcow2") => "qcow2",
|
||||
_ => return Err(anyhow::Error::msg("Can't figure out from path what type of disk driver should be used"))
|
||||
}).to_string()
|
||||
};
|
||||
|
||||
let disk = DiskConfig { disk_type, path };
|
||||
|
||||
// TODO: Add blockdev details
|
||||
|
||||
Ok(disk)
|
||||
}
|
||||
}
|
3
vore-core/src/lib.rs
Normal file
3
vore-core/src/lib.rs
Normal file
|
@ -0,0 +1,3 @@
|
|||
mod instance_config;
|
||||
|
||||
pub use instance_config::*;
|
11
vore/Cargo.toml
Normal file
11
vore/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "vore"
|
||||
version = "0.1.0"
|
||||
authors = ["eater <=@eater.me>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.40"
|
||||
vore-core = { path = "../vore-core" }
|
5
vore/src/main.rs
Normal file
5
vore/src/main.rs
Normal file
|
@ -0,0 +1,5 @@
|
|||
use vore_core::InstanceConfig;
|
||||
|
||||
fn main() {
|
||||
let cfg = InstanceConfig::from_toml(include_str!("../../config/example.toml")).unwrap();
|
||||
}
|
11
vored/Cargo.toml
Normal file
11
vored/Cargo.toml
Normal file
|
@ -0,0 +1,11 @@
|
|||
[package]
|
||||
name = "vored"
|
||||
version = "0.1.0"
|
||||
authors = ["eater <=@eater.me>"]
|
||||
edition = "2018"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
anyhow = "1.0.40"
|
||||
vore-core = { path = "../vore-core" }
|
141
vored/src/instance.rs
Normal file
141
vored/src/instance.rs
Normal file
|
@ -0,0 +1,141 @@
|
|||
use std::fmt::{Display, Formatter};
|
||||
use std::process::Child;
|
||||
use vore_core::InstanceConfig;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Instance {
|
||||
config: InstanceConfig,
|
||||
qemu: Option<Qemu>,
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
pub fn from_config(config: InstanceConfig) -> Instance {
|
||||
Instance { config, qemu: None }
|
||||
}
|
||||
|
||||
pub fn spawn_qemu(&self) -> Result<(), anyhow::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ArgumentList {
|
||||
items: Vec<Argument>,
|
||||
}
|
||||
|
||||
impl Display for ArgumentList {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
let item = self.items.iter().fold(String::new(), |mut x, item| {
|
||||
if x.len() > 0 {
|
||||
x.push_str(" ")
|
||||
}
|
||||
x.push_str(item.as_str());
|
||||
x
|
||||
});
|
||||
f.write_str(&item)
|
||||
}
|
||||
}
|
||||
|
||||
impl ArgumentList {
|
||||
pub fn new(command: &'static str) -> ArgumentList {
|
||||
ArgumentList {
|
||||
items: vec![Argument::Borrowed(command)],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pair(&mut self, key: &'static str, value: String) {
|
||||
self.push(key);
|
||||
self.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PushArgument<T> {
|
||||
fn push(&mut self, argument: T);
|
||||
fn push_pair(&mut self, key: T, value: T) {
|
||||
self.push(key);
|
||||
self.push(value);
|
||||
}
|
||||
}
|
||||
|
||||
impl PushArgument<String> for ArgumentList {
|
||||
fn push(&mut self, argument: String) {
|
||||
self.items.push(Argument::Owned(argument))
|
||||
}
|
||||
}
|
||||
|
||||
impl PushArgument<&'static str> for ArgumentList {
|
||||
fn push(&mut self, argument: &'static str) {
|
||||
self.items.push(Argument::Borrowed(argument))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Argument {
|
||||
Owned(String),
|
||||
Borrowed(&'static str),
|
||||
}
|
||||
|
||||
impl Argument {
|
||||
fn as_str(&self) -> &str {
|
||||
match self {
|
||||
Argument::Owned(owned) => &owned,
|
||||
Argument::Borrowed(borrowed) => borrowed,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build_qemu_command(config: &InstanceConfig) -> ArgumentList {
|
||||
let mut cmd = ArgumentList::new("qemu-system-x86_64");
|
||||
cmd.pair("-name", format!("guest={},debug-threads=on", config.name));
|
||||
|
||||
cmd.push("-S");
|
||||
cmd.push("-no-user-config");
|
||||
cmd.push("-no-defaults");
|
||||
cmd.push("-no-shutdown");
|
||||
|
||||
if config.kvm {
|
||||
cmd.push("-enable-kvm");
|
||||
}
|
||||
|
||||
cmd.pair("-m", config.memory.to_string());
|
||||
|
||||
if config.uefi.enabled {
|
||||
// OVMF will hang if S3 is not disabled
|
||||
// disable S4 too, since libvirt does that 🤷
|
||||
// https://bugs.archlinux.org/task/59465#comment172528
|
||||
cmd.push_pair("-global", "ICH9-LPC.disable_s3=1");
|
||||
cmd.push_pair("-global", "ICH9-LPC.disable_s4=1");
|
||||
}
|
||||
|
||||
cmd.push_pair("-rtc", "driftfix=slew");
|
||||
cmd.push_pair("-serial", "stdio");
|
||||
|
||||
#[cfg(any(target_arch = "x86_64", target_arch = "i686"))]
|
||||
{
|
||||
cmd.push_pair("-global", "kvm-pit.lost_tick_policy=discard")
|
||||
}
|
||||
|
||||
cmd.push("-no-hpet");
|
||||
cmd.push_pair("-boot", "strict=on");
|
||||
|
||||
cmd.pair(
|
||||
"-smp",
|
||||
format!(
|
||||
"{},sockets={},dies={},cores={},threads={}",
|
||||
config.cpu.amount,
|
||||
config.cpu.sockets,
|
||||
config.cpu.dies,
|
||||
config.cpu.cores,
|
||||
config.cpu.threads
|
||||
),
|
||||
);
|
||||
|
||||
cmd.push_pair("-msg", "timestamp=on");
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Qemu {
|
||||
process: Option<Child>,
|
||||
}
|
9
vored/src/main.rs
Normal file
9
vored/src/main.rs
Normal file
|
@ -0,0 +1,9 @@
|
|||
use crate::instance::build_qemu_command;
|
||||
use vore_core::InstanceConfig;
|
||||
|
||||
mod instance;
|
||||
|
||||
fn main() {
|
||||
let cfg = InstanceConfig::from_toml(include_str!("../../config/example.toml")).unwrap();
|
||||
println!("Hello, world! {}", build_qemu_command(&cfg));
|
||||
}
|
Loading…
Reference in a new issue