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