This commit is contained in:
3
agent/Cargo.toml
Normal file
3
agent/Cargo.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[workspace]
|
||||
resolver = "3"
|
||||
members = ["crates/vm"]
|
||||
7
agent/crates/vm/Cargo.toml
Normal file
7
agent/crates/vm/Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
[package]
|
||||
name = "dlx-vm"
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
thiserror = "2.0.14"
|
||||
9
agent/crates/vm/src/error.rs
Normal file
9
agent/crates/vm/src/error.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::qemu::error::QemuError;
|
||||
|
||||
#[derive(Debug, Clone, Error)]
|
||||
pub enum VmError {
|
||||
#[error("QEMU error")]
|
||||
Qemu(#[from] QemuError),
|
||||
}
|
||||
4
agent/crates/vm/src/lib.rs
Normal file
4
agent/crates/vm/src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
mod error;
|
||||
mod model;
|
||||
mod qemu;
|
||||
mod service;
|
||||
3
agent/crates/vm/src/model.rs
Normal file
3
agent/crates/vm/src/model.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
pub mod disk;
|
||||
pub mod net;
|
||||
pub mod vm;
|
||||
7
agent/crates/vm/src/model/disk.rs
Normal file
7
agent/crates/vm/src/model/disk.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Disk {
|
||||
pub file: String,
|
||||
pub index: u32,
|
||||
pub format: Option<String>,
|
||||
pub media: String,
|
||||
}
|
||||
2
agent/crates/vm/src/model/net.rs
Normal file
2
agent/crates/vm/src/model/net.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct VmNet(pub String);
|
||||
15
agent/crates/vm/src/model/vm.rs
Normal file
15
agent/crates/vm/src/model/vm.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use crate::model::{disk::Disk, net::VmNet};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct MemoryMB(pub u32);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct MachineAccel(pub String);
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct CloudInitVM {
|
||||
pub mem: MemoryMB,
|
||||
pub nets: Vec<VmNet>,
|
||||
pub disks: Vec<Disk>,
|
||||
pub machine: MachineAccel,
|
||||
}
|
||||
4
agent/crates/vm/src/qemu.rs
Normal file
4
agent/crates/vm/src/qemu.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod config;
|
||||
pub mod error;
|
||||
pub mod param;
|
||||
pub mod runner;
|
||||
7
agent/crates/vm/src/qemu/config.rs
Normal file
7
agent/crates/vm/src/qemu/config.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use crate::qemu::param::QemuParam;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct QemuConfig {
|
||||
pub executable: String,
|
||||
pub param: QemuParam,
|
||||
}
|
||||
7
agent/crates/vm/src/qemu/error.rs
Normal file
7
agent/crates/vm/src/qemu/error.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Clone, Error)]
|
||||
pub enum QemuError {
|
||||
#[error("unknown qemu error")]
|
||||
Unknown,
|
||||
}
|
||||
158
agent/crates/vm/src/qemu/param.rs
Normal file
158
agent/crates/vm/src/qemu/param.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
use crate::model::{
|
||||
disk::Disk,
|
||||
net::VmNet,
|
||||
vm::{CloudInitVM, MachineAccel, MemoryMB},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct QemuParam(pub String);
|
||||
|
||||
pub trait IntoQemuParam {
|
||||
fn into_qemu_param(self) -> QemuParam;
|
||||
}
|
||||
|
||||
impl IntoQemuParam for MachineAccel {
|
||||
fn into_qemu_param(self) -> QemuParam {
|
||||
QemuParam(format!("-machine accel={}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoQemuParam for MemoryMB {
|
||||
fn into_qemu_param(self) -> QemuParam {
|
||||
QemuParam(format!("-m {}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoQemuParam for VmNet {
|
||||
fn into_qemu_param(self) -> QemuParam {
|
||||
QemuParam(format!("-net {}", self.0))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoQemuParam for Disk {
|
||||
fn into_qemu_param(self) -> QemuParam {
|
||||
let mut v: Vec<String> = vec![];
|
||||
v.push(format!("file={}", self.file));
|
||||
v.push(format!("index={}", self.index));
|
||||
if let Some(format) = self.format {
|
||||
v.push(format!("format={}", format));
|
||||
}
|
||||
v.push(format!("media={}", self.media));
|
||||
|
||||
let v = v.join(",");
|
||||
|
||||
QemuParam(format!("-drive {}", v))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoQemuParam for CloudInitVM {
|
||||
fn into_qemu_param(self) -> QemuParam {
|
||||
let mut params: Vec<QemuParam> = vec![];
|
||||
|
||||
params.push(self.mem.into_qemu_param());
|
||||
|
||||
let nets: Vec<QemuParam> = self
|
||||
.nets
|
||||
.into_iter()
|
||||
.map(IntoQemuParam::into_qemu_param)
|
||||
.collect();
|
||||
params.extend_from_slice(&nets);
|
||||
|
||||
let disks: Vec<QemuParam> = self
|
||||
.disks
|
||||
.into_iter()
|
||||
.map(IntoQemuParam::into_qemu_param)
|
||||
.collect();
|
||||
params.extend_from_slice(&disks);
|
||||
|
||||
params.push(self.machine.into_qemu_param());
|
||||
|
||||
let param = params
|
||||
.into_iter()
|
||||
.map(|e| e.0)
|
||||
.collect::<Vec<String>>()
|
||||
.join(" ");
|
||||
|
||||
QemuParam(param)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::{
|
||||
model::{
|
||||
disk::Disk,
|
||||
net::VmNet,
|
||||
vm::{CloudInitVM, MachineAccel, MemoryMB},
|
||||
},
|
||||
qemu::param::{IntoQemuParam, QemuParam},
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn test_into_qemu_param_disk_format() {
|
||||
let disk = Disk {
|
||||
file: "f".into(),
|
||||
index: 1,
|
||||
format: Some("123".into()),
|
||||
media: "m".into(),
|
||||
};
|
||||
|
||||
let param = disk.into_qemu_param();
|
||||
assert_eq!(
|
||||
param,
|
||||
QemuParam("-drive file=f,index=1,format=123,media=m".into())
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_qemu_param_disk_no_format() {
|
||||
let disk = Disk {
|
||||
file: "f".into(),
|
||||
index: 1,
|
||||
format: None,
|
||||
media: "m".into(),
|
||||
};
|
||||
|
||||
let param = disk.into_qemu_param();
|
||||
assert_eq!(param, QemuParam("-drive file=f,index=1,media=m".into()))
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_qemu_param_mem() {
|
||||
let param = MemoryMB(1024).into_qemu_param();
|
||||
assert_eq!(param, QemuParam("-m 1024".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_qemu_param_machine() {
|
||||
let param = MachineAccel("kvm:tcg".into()).into_qemu_param();
|
||||
assert_eq!(param, QemuParam("-machine accel=kvm:tcg".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_qemu_param_net() {
|
||||
let param = VmNet("nic".into()).into_qemu_param();
|
||||
assert_eq!(param, QemuParam("-net nic".into()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_into_qemu_param_vm() {
|
||||
let vm = CloudInitVM {
|
||||
mem: MemoryMB(1024),
|
||||
nets: vec![VmNet("1".into()), VmNet("2".into())],
|
||||
disks: vec![Disk {
|
||||
file: "f".into(),
|
||||
index: 1,
|
||||
format: None,
|
||||
media: "m".into(),
|
||||
}],
|
||||
machine: MachineAccel("kvm:tcg".into()),
|
||||
};
|
||||
|
||||
let param = vm.into_qemu_param();
|
||||
assert_eq!(
|
||||
param.0,
|
||||
"-m 1024 -net 1 -net 2 -drive file=f,index=1,media=m -machine accel=kvm:tcg"
|
||||
);
|
||||
}
|
||||
}
|
||||
15
agent/crates/vm/src/qemu/runner.rs
Normal file
15
agent/crates/vm/src/qemu/runner.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use std::process::Command;
|
||||
|
||||
use crate::qemu::config::QemuConfig;
|
||||
|
||||
pub fn run_qemu(config: &QemuConfig) {
|
||||
let args: Vec<String> = config
|
||||
.param
|
||||
.clone()
|
||||
.0
|
||||
.split(" ")
|
||||
.map(|s| s.to_string())
|
||||
.collect();
|
||||
|
||||
let handle = Command::new(&config.executable).args(&args).spawn();
|
||||
}
|
||||
1
agent/crates/vm/src/service.rs
Normal file
1
agent/crates/vm/src/service.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod runner;
|
||||
2
agent/crates/vm/src/service/runner.rs
Normal file
2
agent/crates/vm/src/service/runner.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub trait RunnerService {
|
||||
}
|
||||
Reference in New Issue
Block a user