flowey_hvlite/pipelines/
vmm_tests.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4use flowey::node::prelude::ReadVar;
5use flowey::pipeline::prelude::*;
6use flowey_lib_hvlite::_jobs::local_build_and_run_nextest_vmm_tests::VmmTestSelectionFlags;
7use flowey_lib_hvlite::_jobs::local_build_and_run_nextest_vmm_tests::VmmTestSelections;
8use flowey_lib_hvlite::install_vmm_tests_deps::VmmTestsDepSelections;
9use flowey_lib_hvlite::run_cargo_build::common::CommonTriple;
10use std::path::PathBuf;
11use vmm_test_images::KnownTestArtifacts;
12
13#[derive(clap::ValueEnum, Copy, Clone)]
14pub enum VmmTestTargetCli {
15    /// Windows Aarch64
16    WindowsAarch64,
17    /// Windows X64
18    WindowsX64,
19    /// Linux X64
20    LinuxX64,
21}
22
23/// Build everything needed and run the VMM tests
24#[derive(clap::Args)]
25pub struct VmmTestsCli {
26    /// Specify what target to build the VMM tests for
27    ///
28    /// If not specified, defaults to the current host target.
29    #[clap(long)]
30    target: Option<VmmTestTargetCli>,
31
32    /// Directory for the output artifacts
33    #[clap(long)]
34    dir: PathBuf,
35
36    /// Custom test filter
37    #[clap(long, conflicts_with("flags"))]
38    filter: Option<String>,
39    /// Custom list of artifacts to download
40    #[clap(long, conflicts_with("flags"), requires("filter"))]
41    artifacts: Vec<KnownTestArtifacts>,
42    /// Flags used to generate the VMM test filter
43    ///
44    /// Syntax: `--flags=<+|-><flag>,..`
45    ///
46    /// Available flags with default values:
47    ///
48    /// `-tdx,-snp,-hyperv_vbs,+windows,+ubuntu,+freebsd,+linux,+openhcl,+openvmm,+hyperv,+uefi,+pcat,+tmk,+guest_test_uefi`
49    // TODO: Automatically generate the list of possible flags
50    #[clap(long)]
51    flags: Option<VmmTestSelectionFlags>,
52
53    /// pass `--verbose` to cargo
54    #[clap(long)]
55    verbose: bool,
56    /// Automatically install any missing required dependencies.
57    #[clap(long)]
58    install_missing_deps: bool,
59
60    /// Use unstable WHP interfaces
61    #[clap(long)]
62    unstable_whp: bool,
63    /// Release build instead of debug build
64    #[clap(long)]
65    release: bool,
66
67    /// Build only, do not run
68    #[clap(long)]
69    build_only: bool,
70    /// Copy extras to output dir (symbols, etc)
71    #[clap(long)]
72    copy_extras: bool,
73
74    /// Optional: custom kernel modules
75    #[clap(long)]
76    custom_kernel_modules: Option<PathBuf>,
77    /// Optional: custom kernel image
78    #[clap(long)]
79    custom_kernel: Option<PathBuf>,
80}
81
82impl IntoPipeline for VmmTestsCli {
83    fn into_pipeline(self, backend_hint: PipelineBackendHint) -> anyhow::Result<Pipeline> {
84        if !matches!(backend_hint, PipelineBackendHint::Local) {
85            anyhow::bail!("vmm-tests is for local use only")
86        }
87
88        let Self {
89            target,
90            dir,
91            filter,
92            artifacts,
93            flags,
94            verbose,
95            install_missing_deps,
96            unstable_whp,
97            release,
98            build_only,
99            copy_extras,
100            custom_kernel_modules,
101            custom_kernel,
102        } = self;
103
104        let openvmm_repo = flowey_lib_common::git_checkout::RepoSource::ExistingClone(
105            ReadVar::from_static(crate::repo_root()),
106        );
107
108        let mut pipeline = Pipeline::new();
109
110        let target = if let Some(t) = target {
111            t
112        } else {
113            match (
114                FlowArch::host(backend_hint),
115                FlowPlatform::host(backend_hint),
116            ) {
117                (FlowArch::Aarch64, FlowPlatform::Windows) => VmmTestTargetCli::WindowsAarch64,
118                (FlowArch::X86_64, FlowPlatform::Windows) => VmmTestTargetCli::WindowsX64,
119                (FlowArch::X86_64, FlowPlatform::Linux(_)) => VmmTestTargetCli::LinuxX64,
120                _ => anyhow::bail!("unsupported host"),
121            }
122        };
123
124        let target = match target {
125            VmmTestTargetCli::WindowsAarch64 => CommonTriple::AARCH64_WINDOWS_MSVC,
126            VmmTestTargetCli::WindowsX64 => CommonTriple::X86_64_WINDOWS_MSVC,
127            VmmTestTargetCli::LinuxX64 => CommonTriple::X86_64_LINUX_GNU,
128        };
129        let target_os = target.as_triple().operating_system;
130        let target_architecture = target.as_triple().architecture;
131
132        pipeline
133            .new_job(
134                FlowPlatform::host(backend_hint),
135                FlowArch::host(backend_hint),
136                "build vmm test dependencies",
137            )
138            .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_versions::Request {})
139            .dep_on(
140                |_| flowey_lib_hvlite::_jobs::cfg_hvlite_reposource::Params {
141                    hvlite_repo_source: openvmm_repo.clone(),
142                },
143            )
144            .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_common::Params {
145                local_only: Some(flowey_lib_hvlite::_jobs::cfg_common::LocalOnlyParams {
146                    interactive: true,
147                    auto_install: install_missing_deps,
148                    force_nuget_mono: false,
149                    external_nuget_auth: false,
150                    ignore_rust_version: true,
151                }),
152                verbose: ReadVar::from_static(verbose),
153                locked: false,
154                deny_warnings: false,
155            })
156            .dep_on(
157                |ctx| flowey_lib_hvlite::_jobs::local_build_and_run_nextest_vmm_tests::Params {
158                    target,
159                    test_content_dir: dir,
160                    selections: if let Some(filter) = filter {
161                        VmmTestSelections::Custom {
162                            filter,
163                            artifacts,
164                            // TODO: add a way to manually specify these
165                            // For now, just build and install everything.
166                            build: Default::default(),
167                            deps: match target_os {
168                                target_lexicon::OperatingSystem::Windows => {
169                                    VmmTestsDepSelections::Windows {
170                                        hyperv: true,
171                                        whp: true,
172                                        // No hardware isolation support on Aarch64, so don't default to needing it when the
173                                        // user specifies a custom filter.
174                                        hardware_isolation: match target_architecture {
175                                            target_lexicon::Architecture::Aarch64(_) => false,
176                                            target_lexicon::Architecture::X86_64 => true,
177                                            _ => panic!(
178                                                "Unhandled architecture: {:?}",
179                                                target_architecture
180                                            ),
181                                        },
182                                    }
183                                }
184                                target_lexicon::OperatingSystem::Linux => {
185                                    VmmTestsDepSelections::Linux
186                                }
187                                _ => unreachable!(),
188                            },
189                        }
190                    } else {
191                        VmmTestSelections::Flags(flags.unwrap_or_default())
192                    },
193                    unstable_whp,
194                    release,
195                    build_only,
196                    copy_extras,
197                    custom_kernel_modules,
198                    custom_kernel,
199                    done: ctx.new_done_handle(),
200                },
201            )
202            .finish();
203
204        Ok(pipeline)
205    }
206}