Skip to main content

isoloom_spec/
windows.rs

1//! What a Windows guest asks of the VM that runs it: a virtual TPM (Windows 11 expects one),
2//! and how Isoloom reaches it (WinRM, or Windows' own OpenSSH). Each target reads these once,
3//! so a TPM is given, or refused, the same way everywhere.
4
5use crate::images::is_windows;
6use crate::model::VmImpl;
7
8/// Why a VM gets a virtual TPM 2.0.
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub enum Tpm {
11    /// Its OS expects one (Windows 11): given where the target can, left out where it can't,
12    /// since the images Isoloom boots for it install without one.
13    Wanted,
14    /// The spec asks for one (`vm.tpm: true`): a target that gives none refuses the environment.
15    Required,
16}
17
18/// Whether an OS expects a TPM 2.0: Windows 11 refuses to install or upgrade without one.
19#[must_use]
20pub fn expects_tpm(os: &str) -> bool {
21    os == "windows-11"
22}
23
24/// The TPM a VM gets: what `vm.tpm` says, else what its OS expects.
25#[must_use]
26pub fn tpm(vm: &VmImpl) -> Option<Tpm> {
27    match vm.tpm {
28        Some(true) => Some(Tpm::Required),
29        Some(false) => None,
30        None => expects_tpm(&vm.os).then_some(Tpm::Wanted),
31    }
32}
33
34/// Whether a Windows VM is reached over OpenSSH (`vm.image.winssh`) rather than WinRM.
35#[must_use]
36pub fn winssh(vm: &VmImpl) -> bool {
37    is_windows(&vm.os) && vm.image.as_ref().is_some_and(|i| i.winssh)
38}
39
40#[cfg(test)]
41mod tests {
42    use super::*;
43
44    fn vm(os: &str, tpm_field: Option<bool>) -> VmImpl {
45        VmImpl {
46            os: os.into(),
47            provision: Vec::new(),
48            image: None,
49            tpm: tpm_field,
50            boot: None,
51            setup: Vec::new(),
52        }
53    }
54
55    #[test]
56    fn windows_11_wants_a_tpm_and_the_spec_decides_otherwise() {
57        assert_eq!(tpm(&vm("windows-11", None)), Some(Tpm::Wanted));
58        assert_eq!(tpm(&vm("windows-server-2022", None)), None);
59        assert_eq!(tpm(&vm("debian-12", Some(true))), Some(Tpm::Required));
60        assert_eq!(tpm(&vm("windows-11", Some(false))), None);
61    }
62
63    #[test]
64    fn winssh_is_only_for_a_windows_box() {
65        let mut v = vm("windows-server-2022", None);
66        assert!(!winssh(&v));
67        v.image = Some(crate::model::VmImage {
68            winssh: true,
69            ..Default::default()
70        });
71        assert!(winssh(&v));
72        v.os = "debian-12".into();
73        assert!(!winssh(&v));
74    }
75}