implement support for creating domains

This commit is contained in:
Alex Zenla
2024-01-09 15:40:17 -08:00
parent 4b31d95e43
commit 35f3346858
16 changed files with 618 additions and 105 deletions

22
xenclient/Cargo.toml Normal file
View File

@ -0,0 +1,22 @@
[package]
name = "xenclient"
version = "0.0.1"
edition = "2021"
resolver = "2"
[dependencies.xencall]
path = "../xencall"
[dependencies.xenstore]
path = "../xenstore"
[dependencies.uuid]
version = "1.6.1"
features = ["v4"]
[lib]
path = "src/lib.rs"
[[example]]
name = "xenclient-simple"
path = "examples/simple.rs"

View File

@ -0,0 +1,16 @@
use xenclient::create::{DomainConfig, PvDomainConfig};
use xenclient::{XenClient, XenClientError};
fn main() -> Result<(), XenClientError> {
let mut client = XenClient::open()?;
let mut config = DomainConfig::new();
config.configure_cpus(1);
config.configure_memory(524288, 524288, 0);
config.configure_pv(PvDomainConfig::new(
"/boot/vmlinuz-6.1.0-17-amd64".to_string(),
None,
None,
));
client.create(2, config)?;
Ok(())
}

88
xenclient/src/create.rs Normal file
View File

@ -0,0 +1,88 @@
use std::collections::HashMap;
pub struct DomainConfig {
vm_entries: HashMap<String, String>,
domain_entries: HashMap<String, String>,
}
pub struct PvDomainConfig {
kernel: String,
ramdisk: Option<String>,
cmdline: Option<String>,
}
impl DomainConfig {
pub fn new() -> DomainConfig {
DomainConfig {
vm_entries: HashMap::new(),
domain_entries: HashMap::new(),
}
}
pub fn put_vm(&mut self, key: &str, value: String) {
self.vm_entries.insert(key.to_string(), value);
}
pub fn put_vm_str(&mut self, key: &str, value: &str) {
self.put_vm(key, value.to_string());
}
pub fn put_domain(&mut self, key: &str, value: String) {
self.vm_entries.insert(key.to_string(), value);
}
pub fn put_domain_str(&mut self, key: &str, value: &str) {
self.put_domain(key, value.to_string());
}
pub fn configure_memory(&mut self, maxkb: u32, targetkb: u32, videokb: u32) {
self.put_domain("memory/static-max", maxkb.to_string());
self.put_domain("memory/target", targetkb.to_string());
self.put_domain("memory/videoram", videokb.to_string());
}
pub fn configure_cpus(&mut self, maxvcpus: u32) {
for i in 0..maxvcpus {
println!("{}", i);
}
}
pub fn configure_pv(&mut self, pv: PvDomainConfig) {
self.put_vm_str("image/ostype", "linux");
self.put_vm("image/kernel", pv.kernel);
match pv.ramdisk {
None => {}
Some(ramdisk) => self.put_vm("image/ramdisk", ramdisk),
}
match pv.cmdline {
None => {}
Some(cmdline) => self.put_vm("image/cmdline", cmdline),
}
}
pub fn clone_vm_entries(&self) -> HashMap<String, String> {
self.vm_entries.clone()
}
pub fn clone_domain_entries(&self) -> HashMap<String, String> {
self.domain_entries.clone()
}
}
impl Default for DomainConfig {
fn default() -> Self {
DomainConfig::new()
}
}
impl PvDomainConfig {
pub fn new(kernel: String, ramdisk: Option<String>, cmdline: Option<String>) -> PvDomainConfig {
PvDomainConfig {
kernel,
ramdisk,
cmdline,
}
}
}

99
xenclient/src/lib.rs Normal file
View File

@ -0,0 +1,99 @@
pub mod create;
use crate::create::DomainConfig;
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::string::FromUtf8Error;
use xencall::domctl::DomainControl;
use xencall::sys::CreateDomain;
use xencall::{XenCall, XenCallError};
use xenstore::bus::XsdBusError;
use xenstore::client::{XsdClient, XsdInterface};
pub struct XenClient {
store: XsdClient,
call: XenCall,
}
#[derive(Debug)]
pub struct XenClientError {
message: String,
}
impl XenClientError {
pub fn new(msg: &str) -> XenClientError {
XenClientError {
message: msg.to_string(),
}
}
}
impl Display for XenClientError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl Error for XenClientError {
fn description(&self) -> &str {
&self.message
}
}
impl From<std::io::Error> for XenClientError {
fn from(value: std::io::Error) -> Self {
XenClientError::new(value.to_string().as_str())
}
}
impl From<XsdBusError> for XenClientError {
fn from(value: XsdBusError) -> Self {
XenClientError::new(value.to_string().as_str())
}
}
impl From<XenCallError> for XenClientError {
fn from(value: XenCallError) -> Self {
XenClientError::new(value.to_string().as_str())
}
}
impl From<FromUtf8Error> for XenClientError {
fn from(value: FromUtf8Error) -> Self {
XenClientError::new(value.to_string().as_str())
}
}
impl XenClient {
pub fn open() -> Result<XenClient, XenClientError> {
let store = XsdClient::open()?;
let call = XenCall::open()?;
Ok(XenClient { store, call })
}
pub fn create(&mut self, config: DomainConfig) -> Result<(), XenClientError> {
let mut domctl = DomainControl::new(&mut self.call);
let created = domctl.create_domain(CreateDomain::default())?;
let domain = self.store.get_domain_path(created.domid)?;
let vm = self.store.read_string(format!("{}/vm", domain).as_str())?;
let mut tx = self.store.transaction()?;
for (key, value) in config.clone_domain_entries() {
let path = format!("{}/{}", domain, key);
tx.write(path.as_str(), value.into_bytes())?;
}
let domid_path = format!("{}/domid", domain);
tx.write(domid_path.as_str(), created.domid.to_string().into_bytes())?;
for (key, value) in config.clone_domain_entries() {
let path = format!("{}/{}", vm, key);
tx.write(path.as_str(), value.into_bytes())?;
}
tx.commit()?;
Ok(())
}
}