Skip to main content

flowey_lib_hvlite/
init_vmm_tests_content_dir.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Setup directory structure that the VMM tests require to run.
5
6use crate::build_flowey_hvlite::FloweyHvliteOutput;
7use crate::build_guest_test_uefi::GuestTestUefiOutput;
8use crate::build_nextest_vmm_tests::NextestVmmTestsArchive;
9use crate::build_openhcl_igvm_from_recipe::OpenhclIgvmOutput;
10use crate::build_openvmm::OpenvmmOutput;
11use crate::build_openvmm_vhost::OpenvmmVhostOutput;
12use crate::build_pipette::PipetteOutput;
13use crate::build_prep_steps::PrepStepsOutput;
14use crate::build_snp_linux_direct_igvm::SnpLinuxDirectIgvmOutput;
15use crate::build_test_igvm_agent_rpc_server::TestIgvmAgentRpcServerOutput;
16use crate::build_tmk_vmm::TmkVmmOutput;
17use crate::build_tmks::TmksOutput;
18use crate::build_tpm_guest_tests::TpmGuestTestsOutput;
19use crate::build_vmfirmwareigvm_dll::VmfirmwareigvmDllOutput;
20use crate::build_vmgstool::VmgstoolOutput;
21use crate::common::CommonArch;
22use crate::download_release_igvm_files_from_gh::OpenhclReleaseVersion;
23use flowey::node::prelude::*;
24use petri_artifacts_common::artifacts::*;
25use petri_artifacts_core::ArtifactId;
26use petri_artifacts_core::ArtifactTarget;
27use petri_artifacts_vmm_test::artifacts::*;
28
29macro_rules! define_vmm_tests_built_artifacts {
30    (
31        $name:ident,
32        $($artifact:ident(
33            $($variant:ident(
34                ($output_let_expr:expr, $member:ident $(, $none_member:ident)*),
35                $artifact_ty:ty
36            )),* $(,)?
37        ) => $output:ty),* $(,)?
38    ) => {
39        ::paste::paste! {
40            #[derive(Serialize, Deserialize)]
41            pub struct $name<C = VarNotClaimed> {$($(
42                pub [<$artifact _ $variant>]: Option<::flowey::node::prelude::ReadVar<$output, C>>,
43            )*)*}
44
45            impl Default for $name<VarNotClaimed> {
46                fn default() -> Self {
47                    Self {$($(
48                        [<$artifact _ $variant>]: None,
49                    )*)*}
50                }
51            }
52
53            impl $name<VarNotClaimed> {
54                pub fn claim(self, ctx: &mut StepCtx<'_>) -> $name<VarClaimed> {
55                    let Self {$($(
56                        [<$artifact _ $variant>],
57                    )*)*} = self;
58                    $name {$($(
59                        [<$artifact _ $variant>]: [<$artifact _ $variant>].claim(ctx),
60                    )*)*}
61                }
62
63                $(pub fn $artifact(&mut self, target: ArtifactTarget) -> ::anyhow::Result<&mut Option<::flowey::node::prelude::ReadVar<$output>>> {
64                    match &target {
65                        $($artifact_ty::TARGET => Ok(&mut self.[<$artifact _ $variant>]),)*
66                        _ if let Some(target) = retry_as_musl(target.clone()) => {
67                            return self.$artifact(target);
68                        }
69                        _ => Err(anyhow::anyhow!("{} {}", target, concat!("does not exist for ", stringify!($artifact)))),
70                    }
71                })*
72
73                $($(pub fn [<$artifact _ $variant _target>]() -> ::target_lexicon::Triple {
74                    $artifact_ty::TARGET.target_triple().expect("no target triple for artifact")
75                })*)*
76            }
77
78            impl $name<VarClaimed> {
79                pub fn write(self, rt: &mut RustRuntimeServices<'_>, test_content_dir: impl AsRef<Path>) -> ::anyhow::Result<()> {
80                    let Self {$($(
81                        [<$artifact _ $variant>],
82                    )*)*} = self;
83
84
85                    $($(if let Some(artifact) = [<$artifact _ $variant>] {
86                        let dst = test_content_dir
87                            .as_ref()
88                            .join($artifact_ty::relative_path());
89
90                        #[expect(clippy::allow_attributes)]
91                        #[allow(irrefutable_let_patterns, unused_variables)]
92                        let $output_let_expr = rt.read(artifact) else {
93                            ::anyhow::bail!(concat!(
94                                "unexpected variant of ",
95                                stringify!($output),
96                                " for ",
97                                stringify!([<$artifact _ $variant>])
98                            ));
99                        };
100
101                        fs_err::create_dir_all(dst.parent().unwrap())?;
102                        fs_err::copy($member, &dst)?;
103                        dst.make_executable()?;
104                    })*)*
105
106                    Ok(())
107                }
108            }
109
110            #[derive(Serialize, Deserialize)]
111            pub struct [<$name Write>]<C = VarNotClaimed> {$($(
112                pub [<$artifact _ $variant>]: Option<::flowey::node::prelude::WriteVar<$output, C>>,
113            )*)*}
114
115            impl Default for [<$name Write>]<VarNotClaimed> {
116                fn default() -> Self {
117                    Self {$($(
118                        [<$artifact _ $variant>]: None,
119                    )*)*}
120                }
121            }
122
123            impl [<$name Write>]<VarNotClaimed> {
124                pub fn claim(self, ctx: &mut StepCtx<'_>) -> [<$name Write>]<VarClaimed> {
125                    let Self {$($(
126                        [<$artifact _ $variant>],
127                    )*)*} = self;
128                    [<$name Write>] {$($(
129                        [<$artifact _ $variant>]: [<$artifact _ $variant>].claim(ctx),
130                    )*)*}
131                }
132            }
133
134            impl [<$name Write>]<VarClaimed> {
135                pub fn resolve(self, rt: &mut RustRuntimeServices<'_>, test_content_dir: impl AsRef<Path>) -> ::anyhow::Result<()> {
136                    let Self {$($(
137                        [<$artifact _ $variant>],
138                    )*)*} = self;
139
140
141                    $($(if let Some(artifact) = [<$artifact _ $variant>] {
142                        let $member = test_content_dir
143                            .as_ref()
144                            .join($artifact_ty::relative_path());
145
146                        if $member.exists() {
147                            $(let $none_member = None;)*
148                            rt.write(
149                                artifact,
150                                &$output_let_expr,
151                            )
152                        } else {
153                            anyhow::bail!("{} not found", $member.display());
154                        }
155                    })*)*
156
157                    Ok(())
158                }
159            }
160
161            #[derive(Serialize, Deserialize, Default, Debug)]
162            pub struct [<$name Selections>] {$($(
163                pub [<$artifact _ $variant>]: bool,
164            )*)*}
165
166            impl [<$name Selections>] {
167                pub fn resolve_artifact(&mut self, id: &str) -> bool {
168                    match id {
169                        $($($artifact_ty::GLOBAL_UNIQUE_ID => {
170                            self.[<$artifact _ $variant>] = true;
171                            true
172                        })*)*
173                        _ => false
174                    }
175                }
176
177                $(pub fn [<$artifact _for>](&self, target: ArtifactTarget) -> ::anyhow::Result<bool>{
178                    match &target {
179                        $($artifact_ty::TARGET => {
180                            Ok(self.[<$artifact _ $variant>])
181                        })*
182                        _ => Err(anyhow::anyhow!("{} {}", target, concat!("does not exist for ", stringify!($artifact)))),
183                    }
184                }
185
186                pub fn [<require_ $artifact _for>](&mut self, target: ArtifactTarget) -> ::anyhow::Result<PathBuf>{
187                    match &target {
188                        $($artifact_ty::TARGET => {
189                            self.[<$artifact _ $variant>] = true;
190                            Ok($artifact_ty::relative_path())
191                        })*
192                        _ if let Some(target) = retry_as_musl(target.clone()) => {
193                            self.[<require_ $artifact _for>](target)
194                        }
195                        _ => Err(anyhow::anyhow!("{} {}", target, concat!("does not exist for ", stringify!($artifact)))),
196                    }
197                })*
198
199                pub fn new_var_set(&self, ctx: &mut ::flowey::node::prelude::NodeCtx<'_>) -> (
200                    $name,
201                    [<$name Write>],
202                ) {
203                    let mut built_artifacts_read = $name::default();
204                    let mut built_artifacts_write = [<$name Write>]::default();
205
206                    $($(if self.[<$artifact _ $variant>] {
207                        let (read_var, write_var) = ctx.new_var();
208                        built_artifacts_read.[<$artifact _ $variant>] = Some(read_var);
209                        built_artifacts_write.[<$artifact _ $variant>] = Some(write_var);
210                    })*)*
211
212                    (built_artifacts_read, built_artifacts_write)
213                }
214
215                pub fn handles(&self) -> Vec<::petri_artifacts_core::ErasedArtifactHandle> {
216                    let mut handles = Vec::new();
217
218                    $($(if self.[<$artifact _ $variant>] {
219                        handles.push($artifact_ty.erase())
220                    })*)*
221
222                    handles
223                }
224            }
225
226        }
227    };
228}
229
230// Try again with musl target, since some artifacts may only be built for musl
231// to save time. Our musl binaries can also run in gnu environments since they
232// are statically linked.
233fn retry_as_musl(target: ArtifactTarget) -> Option<ArtifactTarget> {
234    let ArtifactTarget::Triple(mut triple) = target else {
235        return None;
236    };
237
238    if matches!(
239        triple.operating_system,
240        target_lexicon::OperatingSystem::Linux
241    ) && !matches!(triple.environment, target_lexicon::Environment::Musl)
242    {
243        triple.environment = target_lexicon::Environment::Musl;
244        Some(ArtifactTarget::Triple(triple))
245    } else {
246        None
247    }
248}
249
250define_vmm_tests_built_artifacts!(
251    VmmTestsBuiltArtifacts,
252    // Artifacts used at the pipeline level.
253    flowey_hvlite(
254        windows_x64(
255            (FloweyHvliteOutput::WindowsBin { exe, pdb }, exe, pdb),
256            host_tools::FLOWEY_HVLITE_WINDOWS_X64
257        ),
258        windows_aarch64(
259            (FloweyHvliteOutput::WindowsBin { exe, pdb }, exe, pdb),
260            host_tools::FLOWEY_HVLITE_WINDOWS_AARCH64
261        ),
262        linux_x64(
263            (FloweyHvliteOutput::LinuxBin { bin, dbg}, bin, dbg),
264            host_tools::FLOWEY_HVLITE_LINUX_X64
265        ),
266    ) => FloweyHvliteOutput,
267    nextest_vmm_tests_archive(
268        windows_x64(
269            (NextestVmmTestsArchive { archive_file }, archive_file),
270            host_tools::NEXTEST_VMM_TESTS_ARCHIVE_WINDOWS_X64
271        ),
272        windows_aarch64(
273            (NextestVmmTestsArchive { archive_file }, archive_file),
274            host_tools::NEXTEST_VMM_TESTS_ARCHIVE_WINDOWS_AARCH64
275        ),
276        linux_x64(
277            (NextestVmmTestsArchive { archive_file }, archive_file),
278            host_tools::NEXTEST_VMM_TESTS_ARCHIVE_LINUX_X64
279        ),
280        linux_musl_x64(
281            (NextestVmmTestsArchive { archive_file }, archive_file),
282            host_tools::NEXTEST_VMM_TESTS_ARCHIVE_LINUX_X64_MUSL
283        ),
284        linux_musl_aarch64(
285            (NextestVmmTestsArchive { archive_file }, archive_file),
286            host_tools::NEXTEST_VMM_TESTS_ARCHIVE_LINUX_AARCH64_MUSL
287        ),
288    ) => NextestVmmTestsArchive,
289    prep_steps(
290        windows_x64(
291            (PrepStepsOutput::WindowsBin { exe, pdb }, exe, pdb),
292            host_tools::PREP_STEPS_WINDOWS_X64
293        ),
294        linux_musl_x64(
295            (PrepStepsOutput::LinuxBin { bin, dbg}, bin, dbg),
296            host_tools::PREP_STEPS_LINUX_X64_MUSL
297        ),
298    ) => PrepStepsOutput,
299    test_igvm_agent_rpc_server(
300        windows_x64(
301            (TestIgvmAgentRpcServerOutput { exe, pdb }, exe, pdb),
302            host_tools::TEST_IGVM_AGENT_RPC_SERVER_WINDOWS_X64
303        ),
304    ) => TestIgvmAgentRpcServerOutput,
305
306    // Artifacts used internally by petri.
307    openvmm(
308        windows_x64(
309            (OpenvmmOutput::WindowsBin { exe, pdb }, exe, pdb),
310            OPENVMM_WINDOWS_X64
311        ),
312        windows_aarch64(
313            (OpenvmmOutput::WindowsBin { exe, pdb }, exe, pdb),
314            OPENVMM_WINDOWS_AARCH64
315        ),
316        linux_x64(
317            (OpenvmmOutput::LinuxBin { bin, dbg}, bin, dbg),
318            OPENVMM_LINUX_X64
319        ),
320        linux_aarch64(
321            (OpenvmmOutput::LinuxBin { bin, dbg}, bin, dbg),
322            OPENVMM_LINUX_AARCH64
323        ),
324        linux_musl_x64(
325            (OpenvmmOutput::LinuxBin { bin, dbg}, bin, dbg),
326            OPENVMM_LINUX_X64_MUSL
327        ),
328        linux_musl_aarch64(
329            (OpenvmmOutput::LinuxBin { bin, dbg}, bin, dbg),
330            OPENVMM_LINUX_AARCH64_MUSL
331        ),
332    ) => OpenvmmOutput,
333    openvmm_vhost(
334        linux_x64(
335            (OpenvmmVhostOutput { bin, dbg}, bin, dbg),
336            OPENVMM_VHOST_LINUX_X64
337        ),
338        linux_aarch64(
339            (OpenvmmVhostOutput { bin, dbg}, bin, dbg),
340            OPENVMM_VHOST_LINUX_AARCH64
341        ),
342        linux_musl_x64(
343            (OpenvmmVhostOutput { bin, dbg}, bin, dbg),
344            OPENVMM_VHOST_LINUX_X64_MUSL
345        ),
346        linux_musl_aarch64(
347            (OpenvmmVhostOutput { bin, dbg}, bin, dbg),
348            OPENVMM_VHOST_LINUX_AARCH64_MUSL
349        ),
350    ) => OpenvmmVhostOutput,
351    pipette(
352        windows_x64(
353            (PipetteOutput::WindowsBin { exe, pdb }, exe, pdb),
354            PIPETTE_WINDOWS_X64
355        ),
356        windows_aarch64(
357            (PipetteOutput::WindowsBin { exe, pdb }, exe, pdb),
358            PIPETTE_WINDOWS_AARCH64
359        ),
360        linux_musl_x64(
361            (PipetteOutput::LinuxBin { bin, dbg}, bin, dbg),
362            PIPETTE_LINUX_X64_MUSL
363        ),
364        linux_musl_aarch64(
365            (PipetteOutput::LinuxBin { bin, dbg}, bin, dbg),
366            PIPETTE_LINUX_AARCH64_MUSL
367        ),
368    ) => PipetteOutput,
369    guest_test_uefi(
370        x64(
371            (GuestTestUefiOutput { img, efi, pdb }, img, efi, pdb),
372            test_vhd::GUEST_TEST_UEFI_X64
373        ),
374        aarch64(
375            (GuestTestUefiOutput { img, efi, pdb }, img, efi, pdb),
376            test_vhd::GUEST_TEST_UEFI_AARCH64
377        ),
378    ) => GuestTestUefiOutput,
379    openhcl_standard(
380        x64(
381            (OpenhclIgvmOutput::X64 { igvm_bin }, igvm_bin),
382            openhcl_igvm::LATEST_STANDARD_X64
383        ),
384        aarch64(
385            (OpenhclIgvmOutput::Aarch64 { igvm_bin }, igvm_bin),
386            openhcl_igvm::LATEST_STANDARD_AARCH64
387        ),
388    ) => OpenhclIgvmOutput,
389    openhcl_standard_dev(
390        x64(
391            (OpenhclIgvmOutput::X64Devkern { igvm_bin }, igvm_bin),
392            openhcl_igvm::LATEST_STANDARD_DEV_KERNEL_X64
393        ),
394        aarch64(
395            (OpenhclIgvmOutput::Aarch64Devkern { igvm_bin }, igvm_bin),
396            openhcl_igvm::LATEST_STANDARD_DEV_KERNEL_AARCH64
397        ),
398    ) => OpenhclIgvmOutput,
399    openhcl_cvm(
400        x64(
401            (OpenhclIgvmOutput::X64Cvm { igvm_bin, endorsements }, igvm_bin, endorsements),
402            openhcl_igvm::LATEST_CVM_X64
403        ),
404    ) => OpenhclIgvmOutput,
405    vmfirmwareigvm_cvm(
406        x64(
407            (VmfirmwareigvmDllOutput { dll }, dll),
408            vmfw_dll::LATEST_CVM_X64
409        ),
410    ) => VmfirmwareigvmDllOutput,
411    openhcl_linux_direct(
412        x64(
413            (OpenhclIgvmOutput::X64TestLinuxDirect { igvm_bin }, igvm_bin),
414            openhcl_igvm::LATEST_LINUX_DIRECT_TEST_X64
415        ),
416    ) => OpenhclIgvmOutput,
417    snp_linux_direct_igvm(
418        x64(
419            (SnpLinuxDirectIgvmOutput { igvm_bin, igvm_map }, igvm_bin, igvm_map),
420            snp_igvm::SNP_LINUX_DIRECT_IGVM_X64
421        ),
422    ) => SnpLinuxDirectIgvmOutput,
423    tmks(
424        x64(
425            (TmksOutput { bin, dbg}, bin, dbg),
426            tmks::SIMPLE_TMK_X64
427        ),
428        aarch64(
429            (TmksOutput { bin, dbg}, bin, dbg),
430            tmks::SIMPLE_TMK_AARCH64
431        ),
432    ) => TmksOutput,
433    tmk_vmm(
434        windows_x64(
435            (TmkVmmOutput::WindowsBin { exe, pdb }, exe, pdb),
436            tmks::TMK_VMM_WINDOWS_X64
437        ),
438        windows_aarch64(
439            (TmkVmmOutput::WindowsBin { exe, pdb }, exe, pdb),
440            tmks::TMK_VMM_WINDOWS_AARCH64
441        ),
442        linux_musl_x64(
443            (TmkVmmOutput::LinuxBin { bin, dbg}, bin, dbg),
444            tmks::TMK_VMM_LINUX_X64_MUSL
445        ),
446        linux_musl_aarch64(
447            (TmkVmmOutput::LinuxBin { bin, dbg}, bin, dbg),
448            tmks::TMK_VMM_LINUX_AARCH64_MUSL
449        ),
450    ) => TmkVmmOutput,
451    vmgstool(
452        windows_x64(
453            (VmgstoolOutput::WindowsBin { exe, pdb }, exe, pdb),
454            vmgstool::VMGSTOOL_WINDOWS_X64
455        ),
456        windows_aarch64(
457            (VmgstoolOutput::WindowsBin { exe, pdb }, exe, pdb),
458            vmgstool::VMGSTOOL_WINDOWS_AARCH64
459        ),
460        linux_x64(
461            (VmgstoolOutput::LinuxBin { bin, dbg}, bin, dbg),
462            vmgstool::VMGSTOOL_LINUX_X64
463        ),
464    ) => VmgstoolOutput,
465    vmgstool_dev(
466        windows_x64(
467            (VmgstoolOutput::WindowsBin { exe, pdb }, exe, pdb),
468            vmgstool::VMGSTOOL_DEV_WINDOWS_X64
469        ),
470        windows_aarch64(
471            (VmgstoolOutput::WindowsBin { exe, pdb }, exe, pdb),
472            vmgstool::VMGSTOOL_DEV_WINDOWS_AARCH64
473        ),
474        linux_x64(
475            (VmgstoolOutput::LinuxBin { bin, dbg}, bin, dbg),
476            vmgstool::VMGSTOOL_DEV_LINUX_X64
477        ),
478    ) => VmgstoolOutput,
479    tpm_guest_tests(
480        windows_x64(
481            (TpmGuestTestsOutput::WindowsBin { exe, pdb }, exe, pdb),
482            guest_tools::TPM_GUEST_TESTS_WINDOWS_X64
483        ),
484        linux_x64(
485            (TpmGuestTestsOutput::LinuxBin { bin, dbg}, bin, dbg),
486            guest_tools::TPM_GUEST_TESTS_LINUX_X64
487        ),
488    ) => TpmGuestTestsOutput,
489);
490
491pub type ResolveVmmTestsBuiltArtifacts =
492    Box<dyn Fn(&mut flowey::pipeline::prelude::PipelineJobCtx<'_>) -> VmmTestsBuiltArtifacts>;
493
494#[macro_export]
495macro_rules! vmm_tests_built_artifacts_builder {
496    (
497        $name:ty,
498        (
499            $($artifact:ident => $output:ty),* $(,)?
500        )
501    ) => {
502        ::paste::paste! {
503            #[derive(Default, Clone)]
504            pub struct $name {
505                $(pub [<use_ $artifact>]: Option<::flowey::pipeline::prelude::UseTypedArtifact<$output>>,)*
506            }
507
508            impl $name {
509                pub fn finish(self) -> Result<$crate::init_vmm_tests_content_dir::ResolveVmmTestsBuiltArtifacts, &'static str> {
510                    let $name {
511                        $([<use_ $artifact>],)*
512                    } = self;
513
514                    $(let [<use_ $artifact>] = [<use_ $artifact>].ok_or(stringify!($artifact))?;)*
515
516                    Ok(Box::new(move |ctx| $crate::init_vmm_tests_content_dir::VmmTestsBuiltArtifacts {
517                        $($artifact: Some(ctx.use_typed_artifact(&[<use_ $artifact>])),)*
518                        .. Default::default()
519                    }))
520                }
521
522                pub fn selections() -> $crate::init_vmm_tests_content_dir::VmmTestsBuiltArtifactsSelections {
523                    let mut selections = $crate::init_vmm_tests_content_dir::VmmTestsBuiltArtifactsSelections::default();
524                    $(selections.$artifact = true;)*
525                    selections
526                }
527            }
528        }
529    };
530}
531
532define_vmm_tests_built_artifacts!(
533    VmmTestsPreBuiltArtifacts,
534    test_linux_kernel(
535        x64(
536            (src, src),
537            loadable::LINUX_DIRECT_TEST_KERNEL_X64
538        ),
539        aarch64(
540            (src, src),
541            loadable::LINUX_DIRECT_TEST_KERNEL_AARCH64
542        ),
543    ) => PathBuf,
544    test_linux_kernel_cca(
545        aarch64(
546            (src, src),
547            loadable::LINUX_DIRECT_TEST_KERNEL_CCA_AARCH64
548        ),
549    ) => PathBuf,
550    test_linux_initrd(
551        x64(
552            (src, src),
553            loadable::LINUX_DIRECT_TEST_INITRD_X64
554        ),
555        aarch64(
556            (src, src),
557            loadable::LINUX_DIRECT_TEST_INITRD_AARCH64
558        ),
559    ) => PathBuf,
560    test_linux_bzimage(
561        x64(
562            (src, src),
563            loadable::LINUX_DIRECT_TEST_BZIMAGE_X64
564        ),
565    ) => PathBuf,
566    uefi(
567        x64(
568            (src, src),
569            loadable::UEFI_FIRMWARE_X64
570        ),
571        aarch64(
572            (src, src),
573            loadable::UEFI_FIRMWARE_AARCH64
574        ),
575    ) => PathBuf,
576    qemu_system_aarch64(
577        linux_x64(
578            (src, src),
579            QEMU_SYSTEM_AARCH64_LINUX_X64
580        ),
581    ) => PathBuf,
582);
583
584flowey_request! {
585    pub struct Request {
586        /// Directory to symlink / copy test contents into. Does not need to be
587        /// empty.
588        pub test_content_dir: ReadVar<PathBuf>,
589        /// What triple VMM tests are built for.
590        ///
591        /// Used to detect cases of running Windows VMM tests via WSL2, and adjusting
592        /// reported paths appropriately.
593        pub vmm_tests_target: target_lexicon::Triple,
594        /// Artifacts used by the tests that are built in the openvmm repo
595        pub built_artifacts: VmmTestsBuiltArtifacts,
596        /// Artifacts to download that are pre-built as part of OpenVMM deps
597        pub prebuilt_artifacts: VmmTestsPreBuiltArtifactsSelections,
598        /// Override the UEFI firmware flavor used by the tests
599        pub uefi_firmware_flavor: Option<crate::download_uefi_mu_msvm::FirmwareFlavor>,
600        /// Copy files necessary to use the test content dir as a minimal repo root.
601        ///
602        /// This is useful for running tests on machines without a local clone.
603        pub is_repo_root: bool,
604
605        // TODO: refactor these last two to use one artifact per arch so that
606        // they can be part of `VmmTestsPreBuiltArtifactsSelections`.
607        pub needs_virtio_win_drivers: bool,
608        pub needs_release_igvm: bool,
609
610        pub done: WriteVar<SideEffect>
611    }
612}
613
614new_simple_flow_node!(struct Node);
615
616impl SimpleFlowNode for Node {
617    type Request = Request;
618
619    fn imports(ctx: &mut ImportCtx<'_>) {
620        ctx.import::<crate::resolve_openvmm_test_initrd::Node>();
621        ctx.import::<crate::resolve_openvmm_test_linux_kernel::Node>();
622        ctx.import::<crate::resolve_openvmm_test_virtio_win::Node>();
623        ctx.import::<crate::git_checkout_openvmm_repo::Node>();
624        ctx.import::<crate::download_uefi_mu_msvm::Node>();
625        ctx.import::<crate::download_release_igvm_files_from_gh::resolve::Node>();
626        ctx.import::<crate::resolve_openvmm_qemu::Node>();
627    }
628
629    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
630        let Request {
631            test_content_dir,
632            vmm_tests_target,
633            built_artifacts,
634            prebuilt_artifacts,
635            uefi_firmware_flavor,
636            is_repo_root,
637            needs_virtio_win_drivers,
638            needs_release_igvm,
639            done,
640        } = request;
641
642        let openvmm_repo_path =
643            is_repo_root.then(|| ctx.reqv(crate::git_checkout_openvmm_repo::req::GetRepoDir));
644
645        let arch = CommonArch::from_architecture(vmm_tests_target.architecture)?;
646
647        let test_linux_initrd_x64 = prebuilt_artifacts.test_linux_initrd_x64.then(|| {
648            ctx.reqv(|v| crate::resolve_openvmm_test_initrd::Request::Get(CommonArch::X86_64, v))
649        });
650        let test_linux_initrd_aarch64 = prebuilt_artifacts.test_linux_initrd_aarch64.then(|| {
651            ctx.reqv(|v| crate::resolve_openvmm_test_initrd::Request::Get(CommonArch::Aarch64, v))
652        });
653        let test_linux_kernel_x64 = prebuilt_artifacts.test_linux_kernel_x64.then(|| {
654            ctx.reqv(|v| {
655                crate::resolve_openvmm_test_linux_kernel::Request::Get(
656                    crate::resolve_openvmm_test_linux_kernel::OpenvmmTestKernelFile::Kernel,
657                    CommonArch::X86_64,
658                    crate::resolve_openvmm_test_linux_kernel::DEFAULT_LINUX_TEST_KERNEL_VERSION,
659                    v,
660                )
661            })
662        });
663        let test_linux_kernel_aarch64 = prebuilt_artifacts.test_linux_kernel_aarch64.then(|| {
664            ctx.reqv(|v| {
665                crate::resolve_openvmm_test_linux_kernel::Request::Get(
666                    crate::resolve_openvmm_test_linux_kernel::OpenvmmTestKernelFile::Kernel,
667                    CommonArch::Aarch64,
668                    crate::resolve_openvmm_test_linux_kernel::DEFAULT_LINUX_TEST_KERNEL_VERSION,
669                    v,
670                )
671            })
672        });
673        let test_linux_kernel_cca_aarch64 =
674            prebuilt_artifacts.test_linux_kernel_cca_aarch64.then(|| {
675                ctx.reqv(|v| {
676                    crate::resolve_openvmm_test_linux_kernel::Request::Get(
677                        crate::resolve_openvmm_test_linux_kernel::OpenvmmTestKernelFile::Kernel,
678                        CommonArch::Aarch64,
679                        crate::resolve_openvmm_test_linux_kernel::CCA_LINUX_TEST_KERNEL_VERSION,
680                        v,
681                    )
682                })
683            });
684        let test_linux_bzimage_x64 = prebuilt_artifacts.test_linux_bzimage_x64.then(|| {
685            ctx.reqv(|v| {
686                crate::resolve_openvmm_test_linux_kernel::Request::Get(
687                    crate::resolve_openvmm_test_linux_kernel::OpenvmmTestKernelFile::BzImage,
688                    CommonArch::X86_64,
689                    crate::resolve_openvmm_test_linux_kernel::DEFAULT_LINUX_TEST_KERNEL_VERSION,
690                    v,
691                )
692            })
693        });
694
695        let uefi_x64 = prebuilt_artifacts.uefi_x64.then(|| {
696            ctx.reqv(|msvm_fd| crate::download_uefi_mu_msvm::Request::GetMsvmFd {
697                arch: CommonArch::X86_64,
698                flavor: uefi_firmware_flavor,
699                msvm_fd,
700            })
701        });
702        let uefi_aarch64 = prebuilt_artifacts.uefi_aarch64.then(|| {
703            ctx.reqv(|msvm_fd| crate::download_uefi_mu_msvm::Request::GetMsvmFd {
704                arch: CommonArch::Aarch64,
705                flavor: uefi_firmware_flavor,
706                msvm_fd,
707            })
708        });
709
710        let qemu_system_aarch64_linux_x64 =
711            prebuilt_artifacts.qemu_system_aarch64_linux_x64.then(|| {
712                ctx.reqv(|v| {
713                    crate::resolve_openvmm_qemu::Request::Get(
714                        crate::resolve_openvmm_qemu::QemuFile::SystemAarch64,
715                        CommonArch::X86_64,
716                        v,
717                    )
718                })
719            });
720
721        let prebuilt_artifacts = VmmTestsPreBuiltArtifacts {
722            test_linux_kernel_x64,
723            test_linux_kernel_aarch64,
724            test_linux_kernel_cca_aarch64,
725            test_linux_initrd_x64,
726            test_linux_initrd_aarch64,
727            test_linux_bzimage_x64,
728            uefi_x64,
729            uefi_aarch64,
730            qemu_system_aarch64_linux_x64,
731        };
732
733        let virtio_win_dir = needs_virtio_win_drivers
734            .then(|| ctx.reqv(crate::resolve_openvmm_test_virtio_win::Request::Get));
735
736        let release_igvm_files = needs_release_igvm.then(|| {
737            ctx.reqv(
738                |v| crate::download_release_igvm_files_from_gh::resolve::Request {
739                    arch,
740                    release_igvm_files: v,
741                    release_version: OpenhclReleaseVersion::latest(),
742                },
743            )
744        });
745
746        ctx.emit_rust_step("setting up vmm_tests content dir", |ctx| {
747            claim_vars!(
748                ctx,
749                (
750                    test_content_dir,
751                    openvmm_repo_path,
752                    // built artifacts
753                    built_artifacts,
754                    // downloaded artifacts
755                    prebuilt_artifacts,
756                    virtio_win_dir,
757                    release_igvm_files,
758                )
759            );
760
761            done.claim(ctx);
762
763            move |rt| {
764                read_vars!(rt, (release_igvm_files, test_content_dir));
765
766                if !test_content_dir.exists() {
767                    fs_err::create_dir_all(&test_content_dir)?
768                };
769
770                if let Some(openvmm_repo_path) = openvmm_repo_path {
771                    let openvmm_repo_path = rt.read(openvmm_repo_path);
772
773                    let nextest_config_file = PathBuf::new().join(".config").join("nextest.toml");
774                    fs_err::create_dir_all(
775                        test_content_dir
776                            .join(&nextest_config_file)
777                            .parent()
778                            .context("no parent")?,
779                    )?;
780                    fs_err::copy(
781                        openvmm_repo_path.join(&nextest_config_file),
782                        test_content_dir.join(&nextest_config_file),
783                    )?;
784
785                    let repo_cargo_toml_file = Path::new("Cargo.toml");
786                    fs_err::copy(
787                        openvmm_repo_path.join(repo_cargo_toml_file),
788                        test_content_dir.join(repo_cargo_toml_file),
789                    )?;
790
791                    let crate_cargo_toml_file = PathBuf::new()
792                        .join("vmm_tests")
793                        .join("vmm_tests")
794                        .join("Cargo.toml");
795                    fs_err::create_dir_all(
796                        test_content_dir
797                            .join(&crate_cargo_toml_file)
798                            .parent()
799                            .context("no parent")?,
800                    )?;
801                    fs_err::copy(
802                        openvmm_repo_path.join(&crate_cargo_toml_file),
803                        test_content_dir.join(&crate_cargo_toml_file),
804                    )?;
805                }
806
807                built_artifacts.write(rt, &test_content_dir)?;
808
809                prebuilt_artifacts.write(rt, &test_content_dir)?;
810
811                if let Some(release_igvm_files) = release_igvm_files {
812                    if let Some(src) = &release_igvm_files.openhcl {
813                        fs_err::copy(
814                            src,
815                            test_content_dir
816                                .join(openhcl_igvm::LATEST_RELEASE_STANDARD_X64::relative_path()),
817                        )?;
818                    }
819
820                    if let Some(src) = &release_igvm_files.openhcl_aarch64 {
821                        fs_err::copy(
822                            src,
823                            test_content_dir.join(
824                                openhcl_igvm::LATEST_RELEASE_STANDARD_AARCH64::relative_path(),
825                            ),
826                        )?;
827                    }
828
829                    if let Some(src) = &release_igvm_files.openhcl_direct {
830                        fs_err::copy(
831                            src,
832                            test_content_dir.join(
833                                openhcl_igvm::LATEST_RELEASE_LINUX_DIRECT_X64::relative_path(),
834                            ),
835                        )?;
836                    }
837                }
838
839                if let Some(virtio_win_dir) = virtio_win_dir {
840                    let src = rt.read(virtio_win_dir);
841                    let dst =
842                        test_content_dir.join(virtio_win::VIRTIO_WINDOWS_DRIVERS::relative_path());
843                    let _ = fs_err::remove_dir_all(&dst);
844                    flowey_lib_common::_util::copy_dir_all(&src, &dst)?;
845                }
846
847                // log the current contents of the dir
848                log::info!("final folder content: {}", test_content_dir.display());
849                fn list_dir(dir: PathBuf, layer: usize) -> anyhow::Result<()> {
850                    if layer > 2
851                        || dir
852                            .file_name()
853                            .and_then(|n| n.to_str())
854                            .is_some_and(|n| ["temp", "test_results"].contains(&n))
855                    {
856                        log::info!("{}- ...", " ".repeat(layer * 2));
857                        return Ok(());
858                    }
859                    for entry in dir.read_dir()? {
860                        let entry = entry?;
861                        log::info!("{}- {}", " ".repeat(layer * 2), entry.file_name().display());
862                        let subdir = entry.path();
863                        if subdir.is_dir() {
864                            list_dir(subdir, layer + 1)?;
865                        }
866                    }
867                    Ok(())
868                }
869                list_dir(test_content_dir, 0)?;
870
871                Ok(())
872            }
873        });
874
875        Ok(())
876    }
877}
878
879/// Utility builders which make it easy to "skim off" artifacts required by VMM
880/// test execution from other pipeline jobs.
881//
882// DEVNOTE: this is pub so internal tests can reuse the same builders
883pub mod vmm_tests_artifact_builders {
884    use super::*;
885
886    vmm_tests_built_artifacts_builder!(
887        VmmTestsArtifactsBuilderLinuxX86,
888        (
889            // windows build machine
890            pipette_windows_x64 => PipetteOutput,
891            // linux build machine
892            nextest_vmm_tests_archive_linux_x64 => NextestVmmTestsArchive,
893            nextest_vmm_tests_archive_linux_musl_x64 => NextestVmmTestsArchive,
894            openvmm_linux_x64 => OpenvmmOutput,
895            openvmm_linux_musl_x64 => OpenvmmOutput,
896            openvmm_vhost_linux_x64 => OpenvmmVhostOutput,
897            pipette_linux_musl_x64 => PipetteOutput,
898            prep_steps_linux_musl_x64 => PrepStepsOutput,
899            snp_linux_direct_igvm_x64 => SnpLinuxDirectIgvmOutput,
900            tmk_vmm_linux_musl_x64 => TmkVmmOutput,
901            // any machine
902            guest_test_uefi_x64 => GuestTestUefiOutput,
903            tmks_x64 => TmksOutput,
904            // aarch64 emulated binaries
905            nextest_vmm_tests_archive_linux_musl_aarch64 => NextestVmmTestsArchive,
906            openvmm_linux_musl_aarch64 => OpenvmmOutput,
907            pipette_linux_musl_aarch64 => PipetteOutput,
908        )
909    );
910
911    vmm_tests_built_artifacts_builder!(
912        VmmTestsArtifactsBuilderLinuxMuslX86,
913        (
914            // windows build machine
915            pipette_windows_x64 => PipetteOutput,
916            // linux build machine
917            nextest_vmm_tests_archive_linux_musl_x64 => NextestVmmTestsArchive,
918            openvmm_linux_musl_x64 => OpenvmmOutput,
919            openvmm_vhost_linux_musl_x64 => OpenvmmVhostOutput,
920            pipette_linux_musl_x64 => PipetteOutput,
921            prep_steps_linux_musl_x64 => PrepStepsOutput,
922            snp_linux_direct_igvm_x64 => SnpLinuxDirectIgvmOutput,
923            tmk_vmm_linux_musl_x64 => TmkVmmOutput,
924            // any machine
925            guest_test_uefi_x64 => GuestTestUefiOutput,
926            tmks_x64 => TmksOutput,
927            // aarch64 emulated binaries
928            nextest_vmm_tests_archive_linux_musl_aarch64 => NextestVmmTestsArchive,
929            openvmm_linux_musl_aarch64 => OpenvmmOutput,
930            pipette_linux_musl_aarch64 => PipetteOutput,
931        )
932    );
933
934    vmm_tests_built_artifacts_builder!(
935        VmmTestsArtifactsBuilderWindowsX86,
936        (
937            // windows build machine
938            nextest_vmm_tests_archive_windows_x64 => NextestVmmTestsArchive,
939            openvmm_windows_x64 => OpenvmmOutput,
940            pipette_windows_x64 => PipetteOutput,
941            tmk_vmm_windows_x64 => TmkVmmOutput,
942            prep_steps_windows_x64 => PrepStepsOutput,
943            vmgstool_windows_x64 => VmgstoolOutput,
944            vmgstool_dev_windows_x64 => VmgstoolOutput,
945            tpm_guest_tests_windows_x64 => TpmGuestTestsOutput,
946            test_igvm_agent_rpc_server_windows_x64 => TestIgvmAgentRpcServerOutput,
947            vmfirmwareigvm_cvm_x64 => VmfirmwareigvmDllOutput,
948            // linux build machine
949            openhcl_standard_x64 => OpenhclIgvmOutput,
950            openhcl_cvm_x64 => OpenhclIgvmOutput,
951            openhcl_linux_direct_x64 => OpenhclIgvmOutput,
952            pipette_linux_musl_x64 => PipetteOutput,
953            tmk_vmm_linux_musl_x64 => TmkVmmOutput,
954            tpm_guest_tests_linux_x64 => TpmGuestTestsOutput,
955            // any machine
956            guest_test_uefi_x64 => GuestTestUefiOutput,
957            tmks_x64 => TmksOutput,
958        )
959    );
960
961    vmm_tests_built_artifacts_builder!(
962        VmmTestsArtifactsBuilderWindowsAarch64,
963        (
964            // windows build machine
965            nextest_vmm_tests_archive_windows_aarch64 => NextestVmmTestsArchive,
966            openvmm_windows_aarch64 => OpenvmmOutput,
967            pipette_windows_aarch64 => PipetteOutput,
968            tmk_vmm_windows_aarch64 => TmkVmmOutput,
969            vmgstool_windows_aarch64 => VmgstoolOutput,
970            vmgstool_dev_windows_aarch64 => VmgstoolOutput,
971            // linux build machine
972            openhcl_standard_aarch64 => OpenhclIgvmOutput,
973            pipette_linux_musl_aarch64 => PipetteOutput,
974            tmk_vmm_linux_musl_aarch64 => TmkVmmOutput,
975            // any machine
976            guest_test_uefi_aarch64 => GuestTestUefiOutput,
977            tmks_aarch64 => TmksOutput,
978        )
979    );
980}