microsoft/openvmm
Publicmirrored fromhttps://github.com/microsoft/openvmmAvailable
flowey/flowey_hvlite/src/pipelines/build_igvm.rs
346lines · modecode
| 1 | // Copyright (c) Microsoft Corporation. |
| 2 | // Licensed under the MIT License. |
| 3 | |
| 4 | //! See [`BuildIgvmCli`] |
| 5 | |
| 6 | use flowey::node::prelude::ReadVar; |
| 7 | use flowey::pipeline::prelude::*; |
| 8 | use flowey_lib_hvlite::build_openhcl_igvm_from_recipe::OpenhclIgvmRecipe; |
| 9 | use flowey_lib_hvlite::build_openhcl_igvm_from_recipe::OpenhclKernelPackage; |
| 10 | use flowey_lib_hvlite::run_cargo_build::common::CommonArch; |
| 11 | use std::path::PathBuf; |
| 12 | |
| 13 | #[derive(clap::ValueEnum, Copy, Clone)] |
| 14 | pub enum OpenhclRecipeCli { |
| 15 | /// Aarch64 OpenHCL |
| 16 | Aarch64, |
| 17 | /// Aarch64 OpenHCL, using the dev kernel in VTL2 |
| 18 | Aarch64Devkern, |
| 19 | /// X64 OpenHCL, with CVM support. |
| 20 | X64Cvm, |
| 21 | /// X64 OpenHCL, with CVM support using the dev kernel in VTL2 |
| 22 | X64CvmDevkern, |
| 23 | /// X64 OpenHCL booting VTL0 using a test linux-direct kernel + initrd (no |
| 24 | /// UEFI). |
| 25 | X64TestLinuxDirect, |
| 26 | /// X64 OpenHCL booting VTL0 using a test linux-direct kernel + initrd (no |
| 27 | /// UEFI), using the dev kernel in VTL2. |
| 28 | X64TestLinuxDirectDevkern, |
| 29 | /// X64 OpenHCL |
| 30 | X64, |
| 31 | /// X64 OpenHCL, using the dev kernel in VTL2 |
| 32 | X64Devkern, |
| 33 | } |
| 34 | |
| 35 | /// Build OpenHCL IGVM files for local development. DO NOT USE IN CI. |
| 36 | #[derive(clap::Args)] |
| 37 | pub struct BuildIgvmCli<Recipe = OpenhclRecipeCli> |
| 38 | where |
| 39 | // Make the recipe generic so that out-of-tree flowey implementations can |
| 40 | // slot in a custom set of recipes to build with. |
| 41 | Recipe: clap::ValueEnum + Clone + Send + Sync + 'static, |
| 42 | { |
| 43 | /// Specify which OpenHCL recipe to build / customize off-of. |
| 44 | /// |
| 45 | /// A "recipe" corresponds to the various standard IGVM SKUs that are |
| 46 | /// actively supported and tested in our build infrastructure. |
| 47 | /// |
| 48 | /// It encodes all the details of what goes into an individual IGVM file, |
| 49 | /// such as what build flags `openvmm_hcl` should be built with, what goes |
| 50 | /// into a VTL2 initrd, what `igvmfilegen` manifest is being used, etc... |
| 51 | pub recipe: Recipe, |
| 52 | |
| 53 | /// Build using release variants of all constituent components. |
| 54 | /// |
| 55 | /// Uses --profile=boot-release for openhcl_boot, --profile=openhcl-ship |
| 56 | /// when building openvmm_hcl, `--min-interactive` vtl2 initrd |
| 57 | /// configuration, `-release.json` manifest variant, etc... |
| 58 | #[clap(long)] |
| 59 | pub release: bool, |
| 60 | |
| 61 | /// pass `--verbose` to cargo |
| 62 | #[clap(long)] |
| 63 | pub verbose: bool, |
| 64 | |
| 65 | /// pass `--locked` to cargo |
| 66 | #[clap(long)] |
| 67 | pub locked: bool, |
| 68 | |
| 69 | /// Automatically install any missing required dependencies. |
| 70 | #[clap(long)] |
| 71 | pub install_missing_deps: bool, |
| 72 | |
| 73 | #[clap(flatten)] |
| 74 | pub customizations: BuildIgvmCliCustomizations, |
| 75 | } |
| 76 | |
| 77 | #[derive(clap::Args)] |
| 78 | #[clap(next_help_heading = "Customizations")] |
| 79 | pub struct BuildIgvmCliCustomizations { |
| 80 | /// Set a custom label for this `build-igvm` invocation. If no label is |
| 81 | /// provided, customized IGVM files will be output with the label |
| 82 | /// `{base_recipe_name}-custom` |
| 83 | #[clap(long, short = 'o')] |
| 84 | pub build_label: Option<String>, |
| 85 | |
| 86 | /// Override which kernel package to use. |
| 87 | #[clap(long)] |
| 88 | pub override_kernel_pkg: Option<KernelPackageKindCli>, |
| 89 | |
| 90 | /// Pass additional features when building openmm_hcl |
| 91 | #[clap(long)] |
| 92 | pub override_openvmm_hcl_feature: Vec<String>, |
| 93 | |
| 94 | /// Override architecture used when building. You probably don't want this - |
| 95 | /// prefer changing the base recipe to something more appropriate. |
| 96 | #[clap(long)] |
| 97 | pub override_arch: Option<BuildIgvmArch>, |
| 98 | |
| 99 | /// Override the json manifest passed to igvmfilegen, none means the |
| 100 | /// debug/release manifest from the base recipe will be used. |
| 101 | #[clap(long)] |
| 102 | pub override_manifest: Option<PathBuf>, |
| 103 | |
| 104 | /// Ensure perf tools are included in the release initrd. |
| 105 | /// |
| 106 | /// Ensures that openvmm_hcl is not stripped, so that perf tools work |
| 107 | /// correctly, and requires that the file be built in `--release` mode, so |
| 108 | /// that perf numbers are more representative of production binaries. |
| 109 | #[clap(long, requires = "release")] |
| 110 | pub with_perf_tools: bool, |
| 111 | |
| 112 | /// Preserve debuginfo in the openvmm_hcl binary in the IGVM file. |
| 113 | /// |
| 114 | /// This increases the VTL2 memory requirements significantly, and will |
| 115 | /// likely require passing a `--override-manifest` to compensate. |
| 116 | #[clap(long)] |
| 117 | pub with_debuginfo: bool, |
| 118 | |
| 119 | /// Path to custom openvmm_hcl binary, none means openhcl will be built. |
| 120 | #[clap(long)] |
| 121 | pub custom_openvmm_hcl: Option<PathBuf>, |
| 122 | |
| 123 | /// Path to custom openhcl_boot, none means the boot loader will be built. |
| 124 | #[clap(long)] |
| 125 | pub custom_openhcl_boot: Option<PathBuf>, |
| 126 | |
| 127 | /// Path to custom uefi MSVM.fd, none means the packaged uefi will be used. |
| 128 | #[clap(long)] |
| 129 | pub custom_uefi: Option<PathBuf>, |
| 130 | |
| 131 | /// Path to custom kernel vmlinux / Image, none means the packaged kernel |
| 132 | /// will be used. |
| 133 | #[clap(long)] |
| 134 | pub custom_kernel: Option<PathBuf>, |
| 135 | |
| 136 | /// Path to kernel modules, none means the packaged kernel modules will be |
| 137 | /// used. |
| 138 | #[clap(long)] |
| 139 | pub custom_kernel_modules: Option<PathBuf>, |
| 140 | |
| 141 | /// Path to custom vtl0 linux kernel to use if the manifest includes a |
| 142 | /// direct-boot linux VM. |
| 143 | /// |
| 144 | /// If not specified, the packaged openvmm test linux direct kernel is used. |
| 145 | #[clap(long)] |
| 146 | pub custom_vtl0_kernel: Option<PathBuf>, |
| 147 | |
| 148 | /// Additional layers to be included in the initrd |
| 149 | #[clap(long)] |
| 150 | pub custom_layer: Vec<PathBuf>, |
| 151 | |
| 152 | /// Additional directories to be included in the initrd |
| 153 | #[clap(long)] |
| 154 | pub custom_directory: Vec<PathBuf>, |
| 155 | |
| 156 | /// Additional rootfs.config files to use to generate the initrd |
| 157 | #[clap(long)] |
| 158 | pub custom_extra_rootfs: Vec<PathBuf>, |
| 159 | |
| 160 | /// (experimental) Include the AP kernel in the IGVM file |
| 161 | #[clap(long)] |
| 162 | pub with_sidecar: bool, |
| 163 | |
| 164 | /// (experimental) Path to custom sidecar kernel binary, none means sidecar |
| 165 | /// will be built. |
| 166 | #[clap(long, requires = "with_sidecar")] |
| 167 | pub custom_sidecar: Option<PathBuf>, |
| 168 | } |
| 169 | |
| 170 | #[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)] |
| 171 | pub enum KernelPackageKindCli { |
| 172 | /// Kernel from the hcl-main branch |
| 173 | Main, |
| 174 | /// CVM kernel from the hcl-main branch |
| 175 | Cvm, |
| 176 | /// Kernel from the hcl-dev branch |
| 177 | Dev, |
| 178 | /// CVM kernel from the hcl-dev brnach |
| 179 | CvmDev, |
| 180 | } |
| 181 | |
| 182 | #[derive(clap::ValueEnum, Copy, Clone, PartialEq, Eq, Debug)] |
| 183 | pub enum BuildIgvmArch { |
| 184 | X86_64, |
| 185 | Aarch64, |
| 186 | } |
| 187 | |
| 188 | pub fn bail_if_running_in_ci() -> anyhow::Result<()> { |
| 189 | const OVERRIDE_ENV: &str = "I_HAVE_A_GOOD_REASON_TO_RUN_BUILD_IGVM_IN_CI"; |
| 190 | |
| 191 | if std::env::var(OVERRIDE_ENV).is_ok() { |
| 192 | return Ok(()); |
| 193 | } |
| 194 | |
| 195 | for ci_env in ["TF_BUILD", "GITHUB_ACTIONS"] { |
| 196 | if std::env::var(ci_env).is_ok() { |
| 197 | log::warn!("Detected that {ci_env} is set"); |
| 198 | log::warn!(""); |
| 199 | log::warn!("Do not use `build-igvm` in CI scripts!"); |
| 200 | log::warn!( |
| 201 | "This is a local-only, inner-dev-loop tool to build IGVM files, with an UNSTABLE CLI." |
| 202 | ); |
| 203 | log::warn!(""); |
| 204 | log::warn!( |
| 205 | "Automated pipelines should use the underlying `flowey` nodes that power build-igvm directly, _without_ relying on its CLI!" |
| 206 | ); |
| 207 | log::warn!(""); |
| 208 | log::warn!( |
| 209 | "If you _really_ know what you're doing, you can set {OVERRIDE_ENV} to disable this error." |
| 210 | ); |
| 211 | anyhow::bail!("attempted to run `build-igvm` in CI") |
| 212 | } |
| 213 | } |
| 214 | |
| 215 | Ok(()) |
| 216 | } |
| 217 | |
| 218 | impl IntoPipeline for BuildIgvmCli { |
| 219 | fn into_pipeline(self, backend_hint: PipelineBackendHint) -> anyhow::Result<Pipeline> { |
| 220 | if !matches!(backend_hint, PipelineBackendHint::Local) { |
| 221 | anyhow::bail!("build-igvm is for local use only") |
| 222 | } |
| 223 | |
| 224 | bail_if_running_in_ci()?; |
| 225 | |
| 226 | let openvmm_repo = flowey_lib_common::git_checkout::RepoSource::ExistingClone( |
| 227 | ReadVar::from_static(crate::repo_root()), |
| 228 | ); |
| 229 | |
| 230 | let Self { |
| 231 | recipe, |
| 232 | release, |
| 233 | verbose, |
| 234 | locked, |
| 235 | install_missing_deps, |
| 236 | customizations: |
| 237 | BuildIgvmCliCustomizations { |
| 238 | build_label, |
| 239 | override_kernel_pkg, |
| 240 | override_openvmm_hcl_feature, |
| 241 | override_arch, |
| 242 | override_manifest, |
| 243 | with_perf_tools, |
| 244 | with_debuginfo, |
| 245 | custom_openvmm_hcl, |
| 246 | custom_openhcl_boot, |
| 247 | custom_uefi, |
| 248 | custom_kernel, |
| 249 | custom_kernel_modules, |
| 250 | custom_vtl0_kernel, |
| 251 | custom_layer, |
| 252 | custom_directory, |
| 253 | with_sidecar, |
| 254 | custom_sidecar, |
| 255 | mut custom_extra_rootfs, |
| 256 | }, |
| 257 | } = self; |
| 258 | |
| 259 | if with_perf_tools { |
| 260 | custom_extra_rootfs.push( |
| 261 | crate::repo_root() |
| 262 | .join("openhcl/perftoolsfs.config") |
| 263 | .clone(), |
| 264 | ); |
| 265 | } |
| 266 | |
| 267 | let mut pipeline = Pipeline::new(); |
| 268 | |
| 269 | let (pub_out_dir, _) = pipeline.new_artifact("build-igvm"); |
| 270 | |
| 271 | pipeline |
| 272 | .new_job( |
| 273 | FlowPlatform::host(backend_hint), |
| 274 | FlowArch::host(backend_hint), |
| 275 | "build-igvm", |
| 276 | ) |
| 277 | .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_versions::Request {}) |
| 278 | .dep_on( |
| 279 | |_| flowey_lib_hvlite::_jobs::cfg_hvlite_reposource::Params { |
| 280 | hvlite_repo_source: openvmm_repo, |
| 281 | }, |
| 282 | ) |
| 283 | .dep_on(|_| flowey_lib_hvlite::_jobs::cfg_common::Params { |
| 284 | local_only: Some(flowey_lib_hvlite::_jobs::cfg_common::LocalOnlyParams { |
| 285 | interactive: true, |
| 286 | auto_install: install_missing_deps, |
| 287 | force_nuget_mono: false, // no oss nuget packages |
| 288 | external_nuget_auth: false, |
| 289 | ignore_rust_version: true, |
| 290 | }), |
| 291 | verbose: ReadVar::from_static(verbose), |
| 292 | locked, |
| 293 | deny_warnings: false, |
| 294 | }) |
| 295 | .dep_on(|ctx| flowey_lib_hvlite::_jobs::local_build_igvm::Params { |
| 296 | artifact_dir: ctx.publish_artifact(pub_out_dir), |
| 297 | done: ctx.new_done_handle(), |
| 298 | |
| 299 | base_recipe: match recipe { |
| 300 | OpenhclRecipeCli::X64 => OpenhclIgvmRecipe::X64, |
| 301 | OpenhclRecipeCli::X64Devkern => OpenhclIgvmRecipe::X64Devkern, |
| 302 | OpenhclRecipeCli::X64TestLinuxDirect => OpenhclIgvmRecipe::X64TestLinuxDirect, |
| 303 | OpenhclRecipeCli::X64TestLinuxDirectDevkern => { |
| 304 | OpenhclIgvmRecipe::X64TestLinuxDirectDevkern |
| 305 | } |
| 306 | OpenhclRecipeCli::X64Cvm => OpenhclIgvmRecipe::X64Cvm, |
| 307 | OpenhclRecipeCli::X64CvmDevkern => OpenhclIgvmRecipe::X64CvmDevkern, |
| 308 | OpenhclRecipeCli::Aarch64 => OpenhclIgvmRecipe::Aarch64, |
| 309 | OpenhclRecipeCli::Aarch64Devkern => OpenhclIgvmRecipe::Aarch64Devkern, |
| 310 | }, |
| 311 | release, |
| 312 | |
| 313 | customizations: flowey_lib_hvlite::_jobs::local_build_igvm::Customizations { |
| 314 | build_label, |
| 315 | override_arch: override_arch.map(|a| match a { |
| 316 | BuildIgvmArch::X86_64 => CommonArch::X86_64, |
| 317 | BuildIgvmArch::Aarch64 => CommonArch::Aarch64, |
| 318 | }), |
| 319 | with_perf_tools, |
| 320 | with_debuginfo, |
| 321 | override_kernel_pkg: override_kernel_pkg.map(|p| match p { |
| 322 | KernelPackageKindCli::Main => OpenhclKernelPackage::Main, |
| 323 | KernelPackageKindCli::Cvm => OpenhclKernelPackage::Cvm, |
| 324 | KernelPackageKindCli::Dev => OpenhclKernelPackage::Dev, |
| 325 | KernelPackageKindCli::CvmDev => OpenhclKernelPackage::CvmDev, |
| 326 | }), |
| 327 | with_sidecar, |
| 328 | custom_extra_rootfs, |
| 329 | override_openvmm_hcl_feature, |
| 330 | custom_sidecar, |
| 331 | override_manifest, |
| 332 | custom_openvmm_hcl, |
| 333 | custom_openhcl_boot, |
| 334 | custom_uefi, |
| 335 | custom_kernel, |
| 336 | custom_kernel_modules, |
| 337 | custom_vtl0_kernel, |
| 338 | custom_layer, |
| 339 | custom_directory, |
| 340 | }, |
| 341 | }) |
| 342 | .finish(); |
| 343 | |
| 344 | Ok(pipeline) |
| 345 | } |
| 346 | } |
| 347 | |