This commit is contained in:
44
.github/workflows/test.yaml
vendored
Normal file
44
.github/workflows/test.yaml
vendored
Normal file
@@ -0,0 +1,44 @@
|
||||
name: Rust CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Set up Rust
|
||||
uses: actions/setup-rust@v2
|
||||
with:
|
||||
rust-version: stable
|
||||
|
||||
- name: Cache Cargo registry
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: ~/.cargo/registry
|
||||
key: ${{ runner.os }}-cargo-registry-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-registry-
|
||||
|
||||
- name: Cache Cargo build
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: target
|
||||
key: ${{ runner.os }}-cargo-build-${{ hashFiles('**/Cargo.lock') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-cargo-build-
|
||||
|
||||
- name: Build
|
||||
run: cargo build --verbose
|
||||
|
||||
- name: Run tests
|
||||
run: cargo test --verbose
|
||||
51
.gitignore
vendored
Executable file
51
.gitignore
vendored
Executable file
@@ -0,0 +1,51 @@
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/rust,rust-analyzer,react
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=rust,rust-analyzer,react
|
||||
|
||||
### react ###
|
||||
.DS_*
|
||||
*.log
|
||||
logs
|
||||
**/*.backup.*
|
||||
**/*.back.*
|
||||
|
||||
.env
|
||||
**/.env
|
||||
.env.*
|
||||
**/.env.*
|
||||
|
||||
node_modules
|
||||
bower_components
|
||||
|
||||
*.sublime*
|
||||
|
||||
psd
|
||||
thumb
|
||||
sketch
|
||||
|
||||
### Rust ###
|
||||
# Generated by Cargo
|
||||
# will have compiled files and executables
|
||||
debug/
|
||||
target/
|
||||
|
||||
# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries
|
||||
# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html
|
||||
Cargo.lock
|
||||
|
||||
# These are backup files generated by rustfmt
|
||||
**/*.rs.bk
|
||||
|
||||
# MSVC Windows builds of rustc generate these, which store debugging information
|
||||
*.pdb
|
||||
|
||||
### rust-analyzer ###
|
||||
# Can be generated by other build systems other than cargo (ex: bazelbuild/rust_rules)
|
||||
rust-project.json
|
||||
|
||||
|
||||
# End of https://www.toptal.com/developers/gitignore/api/rust,rust-analyzer,react
|
||||
|
||||
.venv
|
||||
|
||||
build
|
||||
.VSCodeCounter
|
||||
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