246 lines
6.6 KiB
Rust
246 lines
6.6 KiB
Rust
use log::*;
|
|
|
|
use super::*;
|
|
|
|
#[derive(Default)]
|
|
pub struct DomainBuilder {
|
|
domain: Domain,
|
|
}
|
|
|
|
impl DomainBuilder {
|
|
/// Sets the name attribute of the domain.
|
|
///
|
|
/// From libvirt documentation:
|
|
///
|
|
/// > The content of the name element provides a short
|
|
/// > name for the virtual machine. This name should consist
|
|
/// > only of alphanumeric characters and is required to be
|
|
/// > unique within the scope of a single host. It is often
|
|
/// > used to form the filename for storing the persistent
|
|
/// > configuration file.
|
|
pub fn name(mut self, name: &str) -> Self {
|
|
self.domain.name = name.to_owned();
|
|
self
|
|
}
|
|
|
|
#[cfg(test)]
|
|
pub fn uuid(mut self, uuid: uuid::Uuid) -> Self {
|
|
self.domain.uuid = uuid;
|
|
self
|
|
}
|
|
|
|
/// Sets the title attribute of the domain.
|
|
///
|
|
/// From libvirt documentation:
|
|
///
|
|
/// > The optional element title provides space for a short
|
|
/// > description of the domain. The title should not
|
|
/// > contain any newlines.
|
|
pub fn title(mut self, title: &str) -> Self {
|
|
self.domain.title = Some(title.to_owned());
|
|
self
|
|
}
|
|
|
|
/// Sets the description attribute of the domain.
|
|
///
|
|
/// From libvirt documentation:
|
|
///
|
|
/// > The content of the description element provides a
|
|
/// > human readable description of the virtual machine.
|
|
/// > This data is not used by libvirt in any way, it can
|
|
/// > contain any information the user wants.
|
|
pub fn description(mut self, desc: &str) -> Self {
|
|
self.domain.description = Some(desc.to_owned());
|
|
self
|
|
}
|
|
|
|
/// Sets what action is performed on the domain when
|
|
/// powered off.
|
|
pub fn poweroff_action(mut self, action: PowerAction) -> Self {
|
|
self.domain.on_poweroff = Some(action);
|
|
self
|
|
}
|
|
|
|
/// Sets what action is performed on the domain when
|
|
/// rebooted.
|
|
pub fn reboot_action(mut self, action: PowerAction) -> Self {
|
|
self.domain.on_reboot = Some(action);
|
|
self
|
|
}
|
|
|
|
/// Sets what action is performed on the domain when
|
|
/// it crashes.
|
|
pub fn crash_action(mut self, action: PowerAction) -> Self {
|
|
self.domain.on_crash = Some(action);
|
|
self
|
|
}
|
|
|
|
/// Adds a network interface to the domain.
|
|
pub fn net_device<P>(mut self, net_func: P) -> Self
|
|
where
|
|
P: Fn(IfaceBuilder) -> IfaceBuilder,
|
|
{
|
|
let netdev = net_func(IfaceBuilder::new());
|
|
self.domain.devices.push(Device::Interface {
|
|
interface: netdev.build(),
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Adds a disk device to the domain.
|
|
pub fn disk_device<P>(mut self, disk_func: P) -> Self
|
|
where
|
|
P: Fn(DiskBuilder) -> DiskBuilder,
|
|
{
|
|
let diskdev = disk_func(DiskBuilder::new());
|
|
self.domain.devices.push(Device::Disk {
|
|
disk: diskdev.build(),
|
|
});
|
|
self
|
|
}
|
|
|
|
pub fn memory(mut self, size: SizeInfo) -> Self {
|
|
self.domain.memory = size;
|
|
self
|
|
}
|
|
|
|
pub fn serial_device(mut self, serial_type: SerialType) -> Self {
|
|
self.domain.devices.push(Device::Console {
|
|
console: SerialDevice {
|
|
r#type: serial_type,
|
|
},
|
|
});
|
|
self
|
|
}
|
|
|
|
pub fn cpu_topology(mut self, sockets: u8, dies: u8, cores: u8, threads: u8) -> Self {
|
|
self.domain.cpu.topology = CpuTopology {
|
|
sockets,
|
|
dies,
|
|
cores,
|
|
threads,
|
|
};
|
|
self.domain.vcpu.value = (sockets * dies * cores * threads).into();
|
|
self
|
|
}
|
|
|
|
pub fn build(mut self) -> Domain {
|
|
if self.domain.devices.disk.iter().any(|d| d.boot.is_some()) {
|
|
debug!("Disk has boot order, removing <os/> style boot...");
|
|
self.domain.os.boot = None;
|
|
}
|
|
self.domain
|
|
}
|
|
}
|
|
|
|
pub struct IfaceBuilder {
|
|
iface: NetDevice,
|
|
}
|
|
|
|
impl IfaceBuilder {
|
|
fn new() -> Self {
|
|
Self {
|
|
iface: NetDevice::default(),
|
|
}
|
|
}
|
|
|
|
/// Uses a bridge as the source device.
|
|
pub fn with_bridge(mut self, bridge: &str) -> Self {
|
|
self.iface.r#type = IfaceType::Bridge;
|
|
self.iface.source.bridge = Some(bridge.to_owned());
|
|
self
|
|
}
|
|
|
|
/// Uses a libvirt-defined network as the source device.
|
|
pub fn with_network(mut self, network: &str) -> Self {
|
|
self.iface.r#type = IfaceType::Network;
|
|
self.iface.source.network = Some(network.to_owned());
|
|
self
|
|
}
|
|
|
|
/// Defines the MAC address the interface should use.
|
|
pub fn mac_addr(mut self, addr: &MacAddr) -> Self {
|
|
self.iface.mac = Some(NetMac {
|
|
address: addr.clone(),
|
|
});
|
|
self
|
|
}
|
|
|
|
/// Defines the model type to emulate.
|
|
///
|
|
/// By default, interfaces will be created as virtio. To
|
|
/// see what models you can use on your hypervisor, run:
|
|
///
|
|
/// ```
|
|
/// qemu-system-x86_64 -net nic,model=? /dev/null
|
|
/// ```
|
|
pub fn model(mut self, model: &str) -> Self {
|
|
self.iface.model.r#type = model.to_owned();
|
|
self
|
|
}
|
|
|
|
pub fn target_dev(mut self, name: &str) -> Self {
|
|
self.iface.target = Some(NetTarget {
|
|
dev: name.to_owned(),
|
|
});
|
|
self
|
|
}
|
|
|
|
fn build(self) -> NetDevice {
|
|
self.iface
|
|
}
|
|
}
|
|
|
|
#[derive(Default)]
|
|
pub struct DiskBuilder {
|
|
disk: DiskDevice,
|
|
}
|
|
|
|
impl DiskBuilder {
|
|
pub fn new() -> Self {
|
|
Self::default()
|
|
}
|
|
|
|
/// Set the source for a file
|
|
pub fn file_source(mut self, filename: &str) -> Self {
|
|
self.disk.r#type = DiskType::File;
|
|
self.disk.source.file = Some(filename.to_owned());
|
|
self
|
|
}
|
|
|
|
/// Set the source for a block device
|
|
pub fn block_source(mut self, dev: &str) -> Self {
|
|
self.disk.r#type = DiskType::Block;
|
|
self.disk.source.dev = Some(dev.to_owned());
|
|
self
|
|
}
|
|
|
|
/// Set the source for a volume drive (e.g., zfs)
|
|
pub fn volume_source(mut self, pool: &str, volume: &str) -> Self {
|
|
self.disk.r#type = DiskType::Volume;
|
|
self.disk.source.pool = Some(pool.to_owned());
|
|
self.disk.source.volume = Some(volume.to_owned());
|
|
self
|
|
}
|
|
|
|
/// Set the target for the disk to attach to.
|
|
pub fn target(mut self, dev: &str, bus: &str) -> Self {
|
|
self.disk.target.bus = bus.to_owned();
|
|
self.disk.target.dev = dev.to_owned();
|
|
self
|
|
}
|
|
|
|
pub fn boot_order(mut self, order: u32) -> Self {
|
|
self.disk.boot = Some(DiskBoot { order });
|
|
self
|
|
}
|
|
|
|
pub fn device_type(mut self, devtype: DiskDeviceType) -> Self {
|
|
self.disk.device = devtype;
|
|
self
|
|
}
|
|
|
|
pub fn build(self) -> DiskDevice {
|
|
self.disk
|
|
}
|
|
}
|