use crate::cloudhv::config::{
DeviceConfig, DeviceType, DiskConfig, FsConfig, NetConfig, VfioConfig, VhostUserBlkConfig,
VhostUserNetConfig,
};
use crate::cloudhv::errors::{CloudHypervisorError, Result};
use std::path::PathBuf;
pub struct DeviceBuilder {
device_id: String,
device_type: Option<DeviceType>,
}
impl DeviceBuilder {
pub fn new(id: impl Into<String>) -> Self {
Self {
device_id: id.into(),
device_type: None,
}
}
pub fn disk(mut self, path: impl Into<PathBuf>, readonly: bool) -> Self {
self.device_type = Some(DeviceType::Disk(DiskConfig {
path: path.into(),
readonly,
direct: true,
vhost_user: false,
socket: None,
}));
self
}
pub fn net(mut self, tap: impl Into<String>) -> Self {
self.device_type = Some(DeviceType::Net(NetConfig {
tap: Some(tap.into()),
mac: None,
vhost_user: false,
socket: None,
}));
self
}
pub fn fs(mut self, tag: impl Into<String>, socket: impl Into<PathBuf>) -> Self {
self.device_type = Some(DeviceType::Fs(FsConfig {
tag: tag.into(),
socket: socket.into(),
num_queues: 1,
queue_size: 1024,
cache_size: 8 * 1024 * 1024 * 1024,
}));
self
}
pub fn vhost_user_net(mut self, socket: impl Into<PathBuf>) -> Self {
self.device_type = Some(DeviceType::VhostUserNet(VhostUserNetConfig {
socket: socket.into(),
mac: None,
num_queues: 2,
queue_size: 256,
}));
self
}
pub fn vhost_user_blk(mut self, socket: impl Into<PathBuf>, readonly: bool) -> Self {
self.device_type = Some(DeviceType::VhostUserBlk(VhostUserBlkConfig {
socket: socket.into(),
num_queues: 1,
queue_size: 128,
readonly,
}));
self
}
pub fn vfio(mut self, device: impl Into<String>) -> Self {
self.device_type = Some(DeviceType::Vfio(VfioConfig {
device: device.into(),
}));
self
}
pub fn build(self) -> Result<DeviceConfig> {
let device_type = self.device_type.ok_or_else(|| {
CloudHypervisorError::Device("Device type not specified".to_string())
})?;
Ok(DeviceConfig {
id: self.device_id,
device_type,
})
}
}
pub struct DiskBuilder {
path: Option<PathBuf>,
readonly: bool,
direct: bool,
vhost_user: bool,
socket: Option<PathBuf>,
}
impl DiskBuilder {
pub fn new() -> Self {
Self {
path: None,
readonly: false,
direct: true,
vhost_user: false,
socket: None,
}
}
pub fn path(mut self, path: impl Into<PathBuf>) -> Self {
self.path = Some(path.into());
self
}
pub fn readonly(mut self, readonly: bool) -> Self {
self.readonly = readonly;
self
}
pub fn direct(mut self, direct: bool) -> Self {
self.direct = direct;
self
}
pub fn vhost_user(mut self, socket: impl Into<PathBuf>) -> Self {
self.vhost_user = true;
self.socket = Some(socket.into());
self
}
pub fn build(self) -> Result<DiskConfig> {
let path = self
.path
.ok_or_else(|| CloudHypervisorError::Device("Disk path not specified".to_string()))?;
Ok(DiskConfig {
path,
readonly: self.readonly,
direct: self.direct,
vhost_user: self.vhost_user,
socket: self.socket,
})
}
}
impl Default for DiskBuilder {
fn default() -> Self {
Self::new()
}
}
pub struct NetBuilder {
tap: Option<String>,
mac: Option<String>,
vhost_user: bool,
socket: Option<PathBuf>,
}
impl NetBuilder {
pub fn new() -> Self {
Self {
tap: None,
mac: None,
vhost_user: false,
socket: None,
}
}
pub fn tap(mut self, tap: impl Into<String>) -> Self {
self.tap = Some(tap.into());
self
}
pub fn mac(mut self, mac: impl Into<String>) -> Self {
self.mac = Some(mac.into());
self
}
pub fn vhost_user(mut self, socket: impl Into<PathBuf>) -> Self {
self.vhost_user = true;
self.socket = Some(socket.into());
self
}
pub fn build(self) -> Result<NetConfig> {
if !self.vhost_user && self.tap.is_none() {
return Err(CloudHypervisorError::Device(
"Either tap or vhost_user socket must be specified".to_string(),
));
}
Ok(NetConfig {
tap: self.tap,
mac: self.mac,
vhost_user: self.vhost_user,
socket: self.socket,
})
}
}
impl Default for NetBuilder {
fn default() -> Self {
Self::new()
}
}