flowey_lib_hvlite/
artifact_openhcl_igvm_from_recipe_extras.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Artifact: An artifact containing various "extras" that are generated as part
5//! of the OpenHCL IGVM build. e.g: debug symbols, constituent binaries, etc.
6
7use crate::build_openhcl_igvm_from_recipe::OpenhclIgvmRecipe;
8use flowey::node::prelude::*;
9
10#[derive(Serialize, Deserialize)]
11pub struct OpenhclIgvmExtras {
12    pub recipe: OpenhclIgvmRecipe,
13    pub openvmm_hcl_bin: crate::build_openvmm_hcl::OpenvmmHclOutput,
14    pub openhcl_map: Option<PathBuf>,
15    pub openhcl_boot: crate::build_openhcl_boot::OpenhclBootOutput,
16    pub sidecar: Option<crate::build_sidecar::SidecarOutput>,
17}
18
19/// Publish the artifact.
20pub mod publish {
21    use super::OpenhclIgvmExtras;
22    use crate::build_openhcl_boot::OpenhclBootOutput;
23    use crate::build_openvmm_hcl::OpenvmmHclOutput;
24    use crate::build_sidecar::SidecarOutput;
25    use flowey::node::prelude::*;
26
27    flowey_request! {
28        pub struct Request {
29            pub extras: Vec<ReadVar<OpenhclIgvmExtras>>,
30            pub artifact_dir: ReadVar<PathBuf>,
31            pub done: WriteVar<SideEffect>,
32        }
33    }
34
35    new_simple_flow_node!(struct Node);
36
37    impl SimpleFlowNode for Node {
38        type Request = Request;
39
40        fn imports(ctx: &mut ImportCtx<'_>) {
41            ctx.import::<flowey_lib_common::copy_to_artifact_dir::Node>();
42        }
43
44        fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
45            let Request {
46                extras,
47                artifact_dir,
48                done,
49            } = request;
50
51            let files = ctx.emit_minor_rust_stepv("describe OpenHCL igvm extras artifact", |ctx| {
52                let extras = extras.claim(ctx);
53                |rt| {
54                    let mut files = Vec::new();
55                    for extra in extras {
56                        let OpenhclIgvmExtras {
57                            recipe,
58                            openvmm_hcl_bin,
59                            openhcl_map,
60                            openhcl_boot,
61                            sidecar,
62                        } = rt.read(extra);
63
64                        let folder_name =
65                            crate::artifact_openhcl_igvm_from_recipe::recipe_to_filename(&recipe);
66
67                        {
68                            let OpenvmmHclOutput { bin, dbg } = openvmm_hcl_bin;
69                            files.push((format!("{folder_name}/openvmm_hcl").into(), bin));
70                            if let Some(dbg) = dbg {
71                                files.push((format!("{folder_name}/openvmm_hcl.dbg").into(), dbg));
72                            }
73                        }
74
75                        if let Some(map) = openhcl_map {
76                            files.push((format!("{folder_name}/openhcl.bin.map").into(), map));
77                        }
78
79                        {
80                            let OpenhclBootOutput { bin, dbg } = openhcl_boot;
81                            files.push((format!("{folder_name}/openhcl_boot").into(), bin));
82                            files.push((format!("{folder_name}/openhcl_boot.dbg").into(), dbg));
83                        }
84
85                        if let Some(SidecarOutput { bin, dbg }) = sidecar {
86                            files.push((format!("{folder_name}/sidecar").into(), bin));
87                            files.push((format!("{folder_name}/sidecar.dbg").into(), dbg));
88                        }
89                    }
90                    files
91                }
92            });
93
94            ctx.req(flowey_lib_common::copy_to_artifact_dir::Request {
95                debug_label: "OpenHCL igvm extras".into(),
96                files,
97                artifact_dir,
98                done,
99            });
100
101            Ok(())
102        }
103    }
104}
105
106/// Resolve the contents of an existing artifact.
107pub mod resolve {
108    use super::OpenhclIgvmExtras;
109    use crate::build_openhcl_boot::OpenhclBootOutput;
110    use crate::build_openvmm_hcl::OpenvmmHclOutput;
111    use crate::build_sidecar::SidecarOutput;
112    use flowey::node::prelude::*;
113
114    flowey_request! {
115        pub struct Request {
116            pub artifact_dir: ReadVar<PathBuf>,
117            pub extras: WriteVar<Vec<OpenhclIgvmExtras>>,
118        }
119    }
120
121    new_simple_flow_node!(struct Node);
122
123    impl SimpleFlowNode for Node {
124        type Request = Request;
125
126        fn imports(ctx: &mut ImportCtx<'_>) {
127            ctx.import::<flowey_lib_common::copy_to_artifact_dir::Node>();
128        }
129
130        fn process_request(request: Self::Request, ctx: &mut NodeCtx<'_>) -> anyhow::Result<()> {
131            let Request {
132                artifact_dir,
133                extras,
134            } = request;
135
136            ctx.emit_rust_step("resolve OpenHCL igvm extras artifact", |ctx| {
137                let artifact_dir = artifact_dir.claim(ctx);
138                let extras = extras.claim(ctx);
139                move |rt| {
140                    let artifact_dir = rt.read(artifact_dir);
141
142                    let mut files = Vec::new();
143                    for entry in fs_err::read_dir(artifact_dir)? {
144                        let entry = entry?;
145
146                        if !entry.file_type()?.is_dir() {
147                            anyhow::bail!("unexpected file in root: {:?}", entry.file_name());
148                        }
149
150                        // deny auto-ingest of custom igvm files.
151                        //
152                        // by defn: a "custom" igvm file is no longer "custom"
153                        // when it gets auto-ingested by another job. You get
154                        // into a world of matching filename string, and lose a
155                        // bunch of type-safety...
156                        let recipe = crate::artifact_openhcl_igvm_from_recipe::filename_to_recipe(
157                            entry
158                                .file_name()
159                                .to_str()
160                                .context("unexpected folder name")?,
161                        )
162                        .context("unexpected folder name")?;
163
164                        let folder_name = entry.path();
165                        files.push(OpenhclIgvmExtras {
166                            recipe,
167                            openvmm_hcl_bin: OpenvmmHclOutput {
168                                bin: folder_name.join("openhcl"),
169                                dbg: {
170                                    let p = folder_name.join("openvmm_hcl.dbg");
171                                    p.exists().then_some(p)
172                                },
173                            },
174                            openhcl_map: {
175                                let p = folder_name.join("openhcl.bin.map");
176                                p.exists().then_some(p)
177                            },
178                            openhcl_boot: OpenhclBootOutput {
179                                bin: folder_name.join("openhcl_boot"),
180                                dbg: folder_name.join("openhcl_boot.dbg"),
181                            },
182                            sidecar: Some(SidecarOutput {
183                                bin: folder_name.join("sidecar"),
184                                dbg: folder_name.join("sidecar.dbg"),
185                            }),
186                        })
187                    }
188
189                    rt.write(extras, &files);
190
191                    Ok(())
192                }
193            });
194
195            Ok(())
196        }
197    }
198}