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