use isoloom_plan::hardware::Hardware;
use isoloom_spec::model::{GpuCount, Gpus};
use crate::file::{Deploy, DeviceRequest, Reservations, Service, ServiceDevice};
const ALL_ACCESS: &str = "rwm";
const GPU: &str = "gpu";
pub(super) fn machine(hw: &Hardware, svc: &mut Service) {
svc.devices = hw
.devices
.iter()
.map(|d| ServiceDevice {
source: d.host.clone(),
target: d.guest().to_owned(),
permissions: d.permissions.clone().unwrap_or_else(|| ALL_ACCESS.to_owned()),
})
.collect();
if let Some(g) = &hw.gpus {
let deploy = svc.deploy.get_or_insert_with(Deploy::default);
deploy.resources.reservations = Some(Reservations { devices: vec![request(g)] });
}
}
fn request(g: &Gpus) -> DeviceRequest {
let mut capabilities = vec![GPU.to_owned()];
capabilities.extend(g.capabilities.iter().filter(|c| c.as_str() != GPU).cloned());
let count = match g.count {
Some(GpuCount::All) => Some(serde_yaml_ng::Value::from("all")),
Some(GpuCount::Count(n)) => Some(serde_yaml_ng::Value::from(n)),
None if g.ids.is_empty() => Some(serde_yaml_ng::Value::from(1)),
None => None,
};
DeviceRequest {
capabilities,
driver: g.driver().to_owned(),
count,
device_ids: g.ids.clone(),
options: g.options.clone(),
}
}
#[cfg(test)]
mod tests {
use super::*;
fn hardware(yaml: &str) -> Hardware {
let m: isoloom_spec::model::Machine = serde_yaml_ng::from_str(yaml).unwrap();
Hardware::of(&m)
}
fn yaml(svc: &Service) -> String {
serde_yaml_ng::to_string(svc).unwrap()
}
#[test]
fn devices_are_written_in_long_form() {
let mut svc = Service::default();
machine(&hardware("devices: [/dev/fuse, '/dev/ttyUSB0:/dev/ttyS1:rw']"), &mut svc);
assert_eq!(
yaml(&svc),
"devices:\n- source: /dev/fuse\n target: /dev/fuse\n permissions: rwm\n- source: /dev/ttyUSB0\n target: /dev/ttyS1\n permissions: rw\n"
);
}
#[test]
fn gpus_are_a_device_request_beside_the_limits() {
let mut svc = Service::default();
machine(
&hardware("gpus: { count: all, capabilities: [compute, gpu], options: { virtualization: 'false' } }"),
&mut svc,
);
assert_eq!(
yaml(&svc),
"deploy:\n resources:\n reservations:\n devices:\n - capabilities:\n - gpu\n - compute\n driver: nvidia\n count: all\n options:\n virtualization: 'false'\n"
);
}
#[test]
fn gpus_by_id_name_them_and_their_driver() {
let mut svc = Service::default();
machine(&hardware("gpus: { ids: ['0', GPU-1], driver: cdi }"), &mut svc);
assert!(
yaml(&svc).contains("driver: cdi\n device_ids:\n - '0'\n - GPU-1\n"),
"{}",
yaml(&svc)
);
}
#[test]
fn gpus_without_a_count_or_ids_are_one() {
let mut svc = Service::default();
machine(&hardware("gpus: {}"), &mut svc);
assert!(yaml(&svc).contains("count: 1\n"));
}
}