use std::fmt;
use indexmap::IndexMap;
use isoloom_spec::model::NetworkBoot;
use crate::environment::{MachinePlan, MachineShape};
use crate::requirements::Requirement;
#[must_use]
pub fn requirements(machines: &IndexMap<String, MachinePlan>) -> Option<Requirement> {
machines
.iter()
.find(|(_, mp)| mp.shape == MachineShape::Vm && mp.boot.is_some())
.map(|(name, _)| Requirement::OwnBoot { machine: name.clone() })
}
pub(crate) fn no_own_boot(f: &mut fmt::Formatter<'_>, machine: &str) -> fmt::Result {
write!(
f,
"machine `{machine}` boots its own way (`hardware.boot`): this target boots a VM from its image's own kernel and firmware; Vagrant's libvirt provider boots it"
)
}
#[must_use]
pub fn network_boots(machines: &IndexMap<String, MachinePlan>) -> IndexMap<String, NetworkBoot> {
let mut out = IndexMap::new();
for mp in machines.values().filter(|mp| mp.shape == MachineShape::Vm) {
let Some(n) = mp.boot.as_ref().and_then(|b| b.network.as_ref()) else {
continue;
};
if let Some(net) = mp.addresses.keys().next() {
out.entry(net.clone()).or_insert_with(|| n.clone());
}
}
out
}
#[cfg(test)]
mod tests {
use isoloom_spec::model::Target;
use super::*;
use crate::testing;
const PXE: &str = "version: 1\nname: t\nnetworks: { lan: { cidr: 10.0.0.0/24 } }\nmachines:\n web: { networks: { lan: 10 }, os: debian@12, hardware: { boot: { order: [network, hd], network: { file: pxelinux.0 } } }, app: { image: nginx, steps: [{ run: s.sh }] } }\n";
#[test]
fn only_a_vm_requires_its_own_boot() {
let lab = testing::lab(PXE);
let vm = testing::planned(&lab, Target::Vagrant);
assert!(vm.requirements.contains(&Requirement::OwnBoot { machine: "web".into() }));
assert_eq!(network_boots(&vm.machines)["lan"].file.as_deref(), Some("pxelinux.0"));
let refused = lab.refusal(Target::Docker).expect("a container target refuses it");
assert_eq!(refused.path.as_str(), "machines.web.hardware.boot");
assert!(lab.for_target(Target::Docker).machines["web"].docker.is_none());
}
}