Skip to main content

flowey_lib_hvlite/
init_vmm_tests_env.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Setup the environment variables that the VMM tests require to run.
5
6use flowey::node::prelude::*;
7use petri_artifacts_core::env::*;
8use petri_artifacts_vmm_test::env::*;
9use std::collections::BTreeMap;
10use std::path::Path;
11
12#[derive(Serialize, Deserialize)]
13pub struct PetriParams {
14    /// Disable lazy remote artifact fetching (set PETRI_REMOTE_ARTIFACTS=0).
15    /// Should be true in CI where all images are pre-downloaded.
16    pub disable_remote_artifacts: bool,
17    /// Whether to reuse VHDs created with prep_steps
18    pub reuse_prepped_vhds: bool,
19    /// Tell petri to expect 2mb hugetlb support
20    pub require_2mb_hugetlb: bool,
21}
22
23flowey_request! {
24    pub struct Request {
25        /// Directory to symlink / copy test contents into. Does not need to be
26        /// empty.
27        pub test_content_dir: ReadVar<PathBuf>,
28        /// Specify where VMM tests disk images are stored.
29        pub disk_images_dir: Option<ReadVar<PathBuf>>,
30        /// What triple VMM tests are built for.
31        ///
32        /// Used to detect cases of running Windows VMM tests via WSL2, and adjusting
33        /// reported paths appropriately.
34        pub vmm_tests_target: target_lexicon::Triple,
35        /// Get the path to the folder containing various logs emitted VMM tests.
36        pub get_test_log_path: Option<WriteVar<PathBuf>>,
37
38        /// Parameters to pass to Petri via environment variables
39        pub petri_params: PetriParams,
40
41        /// Get a map of env vars required to be set when running VMM tests
42        pub get_env: WriteVar<BTreeMap<String, String>>,
43    }
44}
45
46new_simple_flow_node!(struct Node);
47
48impl SimpleFlowNode for Node {
49    type Request = Request;
50
51    fn imports(_ctx: &mut ImportCtx<'_>) {}
52
53    fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
54        let Request {
55            test_content_dir,
56            vmm_tests_target,
57            disk_images_dir,
58            get_test_log_path,
59
60            petri_params:
61                PetriParams {
62                    disable_remote_artifacts,
63                    reuse_prepped_vhds,
64                    require_2mb_hugetlb,
65                },
66
67            get_env,
68        } = request;
69
70        // In CI, unstable test failures are non-gating and should be reported as
71        // passing (with a warning). Outside of CI, unstable test failures are
72        // reported as failures unless the user explicitly opts in.
73        let ignore_unstable_failures = !matches!(ctx.backend(), FlowBackend::Local);
74
75        ctx.emit_rust_step("setting up vmm_tests env", |ctx| {
76            let test_content_dir = test_content_dir.claim(ctx);
77            let get_env = get_env.claim(ctx);
78            let get_test_log_path = get_test_log_path.claim(ctx);
79            let disk_image_dir = disk_images_dir.claim(ctx);
80            move |rt| {
81                let test_content_dir = rt.read(test_content_dir);
82
83                let test_log_dir = test_content_dir.join("test_results");
84                let temp_dir = test_content_dir.join("temp");
85
86                let mut env = BTreeMap::new();
87
88                let windows_via_wsl2 = flowey_lib_common::_util::running_in_wsl(rt)
89                    && matches!(
90                        vmm_tests_target.operating_system,
91                        target_lexicon::OperatingSystem::Windows
92                    );
93
94                let disk_image_dir = disk_image_dir.map(|v| rt.read(v));
95
96                // Convert a path via wslpath if running under WSL2,
97                // otherwise just make it absolute.
98                let wsl_convert_path = |path: &Path| -> anyhow::Result<String> {
99                    if windows_via_wsl2 {
100                        flowey_lib_common::_util::wslpath::linux_to_win(rt, path)
101                    } else {
102                        std::path::absolute(path)
103                            .with_context(|| format!("invalid path {}", path.display()))
104                    }
105                    .map(|p| p.to_string_lossy().into())
106                };
107
108                // Eagerly convert all known paths.
109                let converted_content_dir = wsl_convert_path(&test_content_dir)?;
110                let converted_log_dir = wsl_convert_path(&test_log_dir)?;
111                let converted_temp_dir = wsl_convert_path(&temp_dir)?;
112                let converted_disk_image_dir = disk_image_dir
113                    .as_ref()
114                    .map(|p| wsl_convert_path(p))
115                    .transpose()?;
116
117                if !test_content_dir.exists() {
118                    fs_err::create_dir_all(&test_content_dir)?
119                };
120
121                env.insert(VMM_TESTS_CONTENT_DIR.into(), converted_content_dir);
122
123                if test_log_dir.exists() {
124                    fs_err::remove_dir_all(&test_log_dir)?;
125                };
126                fs_err::create_dir(&test_log_dir)?;
127                env.insert(TEST_OUTPUT_PATH.into(), converted_log_dir);
128
129                if temp_dir.exists() {
130                    fs_err::remove_dir_all(&temp_dir)?;
131                };
132                fs_err::create_dir(&temp_dir)?;
133
134                if matches!(rt.platform().kind(), FlowPlatformKind::Windows) || windows_via_wsl2 {
135                    env.insert("TEMP".into(), converted_temp_dir.clone());
136                    env.insert("TMP".into(), converted_temp_dir.clone());
137                    env.insert("SystemTemp".into(), converted_temp_dir);
138                } else {
139                    env.insert("TMPDIR".into(), converted_temp_dir);
140                }
141
142                if let Some(disk_image_dir) = converted_disk_image_dir {
143                    env.insert(VMM_TEST_IMAGES.into(), disk_image_dir);
144                }
145
146                if disable_remote_artifacts {
147                    env.insert(PETRI_REMOTE_ARTIFACTS.into(), "0".into());
148                }
149
150                if reuse_prepped_vhds {
151                    env.insert(PETRI_REUSE_PREPPED_VHDS.into(), "1".into());
152                }
153
154                if ignore_unstable_failures {
155                    env.insert(PETRI_IGNORE_UNSTABLE_FAILURES.into(), "1".into());
156                }
157
158                if require_2mb_hugetlb {
159                    env.insert(OPENVMM_REQUIRE_2MB_HUGETLB.into(), "1".into());
160                };
161
162                rt.write(get_env, &env);
163
164                if let Some(var) = get_test_log_path {
165                    rt.write(var, &test_log_dir)
166                }
167
168                Ok(())
169            }
170        });
171
172        Ok(())
173    }
174}