Skip to main content

petri_artifacts_common/
lib.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! `petri` test artifact declarations used by all petri-based tests, no matter
5//! what VMM backend is being used.
6
7#![forbid(unsafe_code)]
8
9/// Runtime capabilities that VMM tests can require.
10pub mod capabilities {
11    /// Software VPCI device emulation support.
12    pub const VPCI: &str = "vpci";
13
14    /// Support for resetting a partition running Windows.
15    pub const WINDOWS_PARTITION_RESET: &str = "windows_partition_reset";
16
17    /// All capability names known to petri, including those defined by
18    /// incubators. Incubator device capabilities are the device's profile
19    /// `name` with `-` replaced by `_` (e.g. `edu-initiator` → `edu_initiator`).
20    pub const KNOWN_CAPABILITIES: &[&str] = &[
21        VPCI,
22        WINDOWS_PARTITION_RESET,
23        "test_disk",
24        "edu_initiator",
25        "ivshmem_target",
26    ];
27
28    /// Returns `name` if it is a known capability name.
29    pub fn known(name: &str) -> Option<&'static str> {
30        KNOWN_CAPABILITIES
31            .iter()
32            .copied()
33            .find(|capability| *capability == name)
34    }
35
36    /// Returns whether `name` is a known capability name.
37    pub fn is_known_name(name: &str) -> bool {
38        known(name).is_some()
39    }
40}
41
42/// Artifact declarations
43pub mod artifacts {
44    use petri_artifacts_core::declare_artifacts;
45
46    declare_artifacts! {
47        /// Pipette windows x86_64 executable
48        PIPETTE_WINDOWS_X64,
49        /// Pipette linux x86_64 executable
50        PIPETTE_LINUX_X64,
51        /// Pipette windows aarch64 executable
52        PIPETTE_WINDOWS_AARCH64,
53        /// Pipette linux aarch64 executable
54        PIPETTE_LINUX_AARCH64,
55        /// Directory to put petri test logs in
56        TEST_LOG_DIRECTORY,
57    }
58}
59
60/// Artifact tag trait declarations
61pub mod tags {
62    use petri_artifacts_core::ArtifactId;
63
64    /// A coarse-grained label used to differentiate between different OS
65    /// environments.
66    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
67    #[expect(missing_docs)] // Self-describing names.
68    pub enum OsFlavor {
69        Windows,
70        Linux,
71        FreeBsd,
72        Uefi,
73    }
74
75    /// The machine architecture supported by the artifact or VM.
76    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
77    #[expect(missing_docs)] // Self describing names
78    pub enum MachineArch {
79        X86_64,
80        Aarch64,
81    }
82
83    impl MachineArch {
84        /// Returns the host's architecture.
85        pub fn host() -> Self {
86            // xtask-fmt allow-target-arch oneoff-petri-host-arch
87            if cfg!(target_arch = "x86_64") {
88                Self::X86_64
89            }
90            // xtask-fmt allow-target-arch oneoff-petri-host-arch
91            else if cfg!(target_arch = "aarch64") {
92                Self::Aarch64
93            } else {
94                panic!("unsupported host architecture")
95            }
96        }
97    }
98
99    /// Quirks needed to boot a guest.
100    #[derive(Default, Clone, Debug)]
101    pub struct GuestQuirksInner {
102        /// How long to wait after the shutdown IC reports ready before sending
103        /// the shutdown command.
104        ///
105        /// This is necessary because some guests will ignore shutdown requests
106        /// that arrive too early in the boot process.
107        pub hyperv_shutdown_ic_sleep: Option<std::time::Duration>,
108        /// Some guests reboot automatically soon after first boot.
109        pub initial_reboot: Option<InitialRebootCondition>,
110    }
111
112    /// Some guests may automatically reboot only in certain configurations
113    #[derive(Clone, Copy, Debug)]
114    pub enum InitialRebootCondition {
115        /// This guest always reboots on this VMM.
116        Always,
117        /// This guest only reboots when the TPM is enabled.
118        WithTpm,
119    }
120
121    /// Quirks needed to boot a guest, allowing for differences based on backend
122    #[derive(Default, Clone, Debug)]
123    pub struct GuestQuirks {
124        /// Quirks when running in OpenVMM
125        pub openvmm: GuestQuirksInner,
126        /// Quirks when running in Hyper-V
127        pub hyperv: GuestQuirksInner,
128    }
129
130    impl GuestQuirks {
131        /// Use the same quirks for all backends
132        pub fn for_all_backends(quirks: GuestQuirksInner) -> GuestQuirks {
133            GuestQuirks {
134                openvmm: quirks.clone(),
135                hyperv: quirks,
136            }
137        }
138    }
139
140    /// Artifact is a OpenHCL IGVM file
141    pub trait IsOpenhclIgvm: IsLoadable + ArtifactId {}
142
143    /// Artifact is a bootable test VHD file
144    pub trait IsTestVhd: ArtifactId {
145        /// What [`OsFlavor`] this image boots into.
146        const OS_FLAVOR: OsFlavor;
147
148        /// What [`MachineArch`] this image supports.
149        const ARCH: MachineArch;
150
151        /// Declare any "quirks" needed to boot the image.
152        fn quirks() -> GuestQuirks {
153            GuestQuirks::default()
154        }
155    }
156
157    /// Artifact is a bootable test ISO file
158    pub trait IsTestIso: ArtifactId {
159        /// What [`OsFlavor`] this image boots into.
160        const OS_FLAVOR: OsFlavor;
161
162        /// What [`MachineArch`] this image supports.
163        const ARCH: MachineArch;
164
165        /// Declare any "quirks" needed to boot the image.
166        fn quirks() -> GuestQuirks {
167            GuestQuirks::default()
168        }
169    }
170
171    /// Artifact is a binary that can be loaded into a VM
172    pub trait IsLoadable: ArtifactId {
173        /// What [`MachineArch`] this artifact supports.
174        const ARCH: MachineArch;
175    }
176
177    /// Artifact is a test VMGS file
178    pub trait IsTestVmgs: ArtifactId {}
179
180    /// Artifact is a VmgsTool binary
181    pub trait IsVmgsTool: ArtifactId {}
182}