From 90a2bc40404b29954aed780086d3cbe73b7bb8b9 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 7 May 2024 09:26:04 -0700 Subject: [PATCH 1/4] teach Propolis a -v flag with Git metadata Currently, Propolis, both -server and -standalone, opaquely *run* with no hint available about the provenance of the binary. For binaries that come from product software releases, this is basically fine, as those packages include a sha256 of the packaged Propolis zone and one can work from a binary to a source commit. For any development-time experience, random `propolis-standalone`s we've left around, or VMM binaries one finds on a particularly scrumptious USB stick in a parking lot, a `--version flag telling you where the binary probably came from would go a long way. This branch adds a `build.rs` script that uses [the `vergen` crate][1] to emit information about the Git revision that Propolis was build from. Now, we can generate a version string that describes the git branch, commit hash, and commit depth. This is generated in a `propolis::version()` function, which also includes the detected bhyve and viona API versions at runtime. This results in version strings like: ``` propolis-standalone v0.1.0-930 (DIRTY b428c40ef) HEAD, bhyve API v18, viona API v6 ``` In addition to the `--version` flag described above, this commit also has propolis-server and propolis-standalone print version information when run in a way that they will later run a VM. In release software this can provide evidence of a propolis-server which generated a log file. For the rest of us, hopefully the log line isn't lost to backscroll if an issue has occurred.. [1]: https://docs.rs/vergen --- Cargo.lock | 125 ++++++++++++++++++++++------ Cargo.toml | 2 +- bin/propolis-server/src/main.rs | 2 +- bin/propolis-standalone/src/main.rs | 1 + lib/propolis/Cargo.toml | 4 + lib/propolis/build.rs | 18 ++++ lib/propolis/src/lib.rs | 74 ++++++++++++++++ 7 files changed, 197 insertions(+), 29 deletions(-) create mode 100644 lib/propolis/build.rs diff --git a/Cargo.lock b/Cargo.lock index 9efee6dcb..d38004038 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "acpi_tables" @@ -149,12 +149,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" -dependencies = [ - "backtrace", -] +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "api_identity" @@ -602,6 +599,31 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "bon" +version = "3.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a602c73c7b0148ec6d12af6fd5cc7a46e2eacc8878271a999abac56eed12f561" +dependencies = [ + "bon-macros", + "rustversion", +] + +[[package]] +name = "bon-macros" +version = "3.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dee98b0db6a962de883bf5d20362dee4d7ca0d12fe39a7c6c73c844e1cd7c1f" +dependencies = [ + "darling 0.23.0", + "ident_case", + "prettyplease", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.117", +] + [[package]] name = "bootstore" version = "0.1.0" @@ -1407,8 +1429,8 @@ dependencies = [ "toml 1.1.2+spec-1.1.0", "twox-hash", "uuid", - "vergen", - "vergen-git2", + "vergen 9.1.0", + "vergen-git2 9.1.0", ] [[package]] @@ -1791,12 +1813,11 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.3" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d630bccd429a5bb5a64b5e94f693bfc48c9f8566418fda4c494cc94f911f87cc" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -3002,6 +3023,18 @@ dependencies = [ "url", ] +[[package]] +name = "git2" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddddbf932745a6be37109b6112d3ee09696106f848449069d3a57bba937ab82e" +dependencies = [ + "bitflags 2.9.4", + "libc", + "libgit2-sys", + "log", +] + [[package]] name = "glob" version = "0.3.3" @@ -4195,9 +4228,9 @@ source = "git+https://github.com/oxidecomputer/dlpi-sys#555fa6e1315a64f40c72716e [[package]] name = "libgit2-sys" -version = "0.18.2+1.9.1" +version = "0.18.7+1.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c42fe03df2bd3c53a3a9c7317ad91d80c81cd1fb0caec8d7cc4cd2bfa10c222" +checksum = "23c7391e4b9f4ffab1a624223cc1d7385ff9a678f490768add717de7ea2f4d89" dependencies = [ "cc", "libc", @@ -4886,9 +4919,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" +checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441" [[package]] name = "num-derive" @@ -6730,6 +6763,7 @@ dependencies = [ "tokio", "usdt 0.6.0", "uuid", + "vergen-git2 10.0.1", "viona_api", "vm-attest", "zerocopy 0.8.27", @@ -9344,12 +9378,11 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", - "itoa", "libc", "num-conv", "num_threads", @@ -9361,15 +9394,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" dependencies = [ "num-conv", "time-core", @@ -10419,7 +10452,19 @@ dependencies = [ "regex", "rustc_version 0.4.1", "rustversion", - "vergen-lib", + "vergen-lib 9.1.0", +] + +[[package]] +name = "vergen" +version = "10.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5574dd2f922b1a46a06a4b1dc11193a4012108fd54cf725e1816cb8183d8778" +dependencies = [ + "anyhow", + "bon", + "rustversion", + "vergen-lib 10.0.1", ] [[package]] @@ -10430,11 +10475,26 @@ checksum = "d51ab55ddf1188c8d679f349775362b0fa9e90bd7a4ac69838b2a087623f0d57" dependencies = [ "anyhow", "derive_builder", - "git2", + "git2 0.20.2", "rustversion", "time", - "vergen", - "vergen-lib", + "vergen 9.1.0", + "vergen-lib 9.1.0", +] + +[[package]] +name = "vergen-git2" +version = "10.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "410e2f72acce10471037150cd9c585ee7b54560f348bf70cd5fc8e87d3433e45" +dependencies = [ + "anyhow", + "bon", + "git2 0.21.0", + "rustversion", + "time", + "vergen 10.0.1", + "vergen-lib 10.0.1", ] [[package]] @@ -10448,6 +10508,17 @@ dependencies = [ "rustversion", ] +[[package]] +name = "vergen-lib" +version = "10.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cd42fd155c2c2971f6d00face12ec245fbb604fce011ccaf2306d014c2e97ca" +dependencies = [ + "anyhow", + "bon", + "rustversion", +] + [[package]] name = "version_check" version = "0.9.5" diff --git a/Cargo.toml b/Cargo.toml index 2ade0febf..b6b230d6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -190,9 +190,9 @@ tracing-bunyan-formatter = "0.3.3" tracing-subscriber = "0.3.14" usdt = { version = "0.6", default-features = false } uuid = "1.3.2" +vergen-git2 = { version = "10.0.0" } zerocopy = "0.8.25" - # # It's common during development to use a local copy of various complex # dependencies. If you want to use those, uncomment one of these blocks. diff --git a/bin/propolis-server/src/main.rs b/bin/propolis-server/src/main.rs index 329ea05a1..c95baab55 100644 --- a/bin/propolis-server/src/main.rs +++ b/bin/propolis-server/src/main.rs @@ -73,7 +73,7 @@ fn parse_log_level(s: &str) -> anyhow::Result { } #[derive(Debug, Parser)] -#[clap(about, version)] +#[clap(about, version = propolis::version())] /// An HTTP server providing access to Propolis enum Args { /// Runs the Propolis server. diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index 9e61cca10..cc9be47d9 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1591,6 +1591,7 @@ fn api_version_checks(log: &slog::Logger) -> std::io::Result<()> { } #[derive(clap::Parser)] +#[clap(version = propolis::version())] /// Propolis command-line frontend for running a VM. struct Args { /// Either the VM config file or a previously captured snapshot image. diff --git a/lib/propolis/Cargo.toml b/lib/propolis/Cargo.toml index 180f1ae31..39abac044 100644 --- a/lib/propolis/Cargo.toml +++ b/lib/propolis/Cargo.toml @@ -57,6 +57,10 @@ softnpu = { workspace = true, optional = true } dlpi = { workspace = true, optional = true } static_assertions = "1.1.0" +[build-dependencies] +anyhow.workspace = true +vergen-git2.workspace = true + [dev-dependencies] crossbeam-channel.workspace = true tempfile.workspace = true diff --git a/lib/propolis/build.rs b/lib/propolis/build.rs new file mode 100644 index 000000000..253d8f083 --- /dev/null +++ b/lib/propolis/build.rs @@ -0,0 +1,18 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +fn main() -> anyhow::Result<()> { + let git2 = vergen_git2::Git2::builder() + .branch(true) + .commit_count(true) + .dirty(true) + .sha(true) + .build(); + vergen_git2::Emitter::default() + .idempotent() + .add_instructions(&git2)? + .emit()?; + + Ok(()) +} diff --git a/lib/propolis/src/lib.rs b/lib/propolis/src/lib.rs index d11a3aa4c..ce9ae13ce 100644 --- a/lib/propolis/src/lib.rs +++ b/lib/propolis/src/lib.rs @@ -39,3 +39,77 @@ pub mod vsock; pub use exits::{VmEntry, VmExit}; pub use vmm::Machine; + +pub fn version() -> &'static str { + lazy_static::lazy_static! { + static ref VERSION: String = { + use std::fmt::Write; + + let git = match ( + option_env!("VERGEN_GIT_BRANCH"), + option_env!("VERGEN_GIT_SHA"), + option_env!("VERGEN_GIT_COMMIT_COUNT"), + option_env!("VERGEN_GIT_DIRTY"), + ) { + (Some(branch), Some(sha), Some(commit), Some(dirty)) => { + Some((branch, sha, commit, dirty)) + }, + _ => { + None + } + }; + + let mut version = format!("v{}", env!("CARGO_PKG_VERSION")); + if let Some((branch, sha, commit, dirty)) = git { + write!(version, "-{commit} ").unwrap(); + let sha_prefix = sha.get(..9).unwrap_or(sha); + if dirty == "true" { + write!(version, "(DIRTY {sha_prefix}) ").unwrap(); + } else { + write!(version, "({sha_prefix}) ").unwrap(); + } + write!(version, "{branch}").unwrap(); + } else { + version.push_str(" "); + } + + version.push_str(", "); + match bhyve_api::api_version() { + Ok(v) => { + write!(version, "bhyve API v{v}") + .expect("writing to a string never fails"); + } + Err(_) => { + version.push_str(""); + } + } + + version.push_str(", "); + match viona_api::api_version() { + Ok(v) => { + write!(version, "viona API v{v}") + .expect("writing to a string never fails"); + } + Err(_) => { + version.push_str(""); + } + } + + version + }; + }; + &VERSION +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn print_version() { + let v = version(); + eprintln!("propolis {v}"); + assert!(version.contains(env!("CARGO_PKG_VERSION"))); + assert!(version.contains("Bhyve API")); + } +} From c948d027a83f532864f9fcb63d6da9aca97773ef Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 12 Aug 2026 01:58:06 +0000 Subject: [PATCH 2/4] info the version at start, fix test --- bin/propolis-server/src/main.rs | 2 ++ bin/propolis-standalone/src/main.rs | 2 ++ lib/propolis/src/lib.rs | 5 +++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bin/propolis-server/src/main.rs b/bin/propolis-server/src/main.rs index c95baab55..42fcc37c3 100644 --- a/bin/propolis-server/src/main.rs +++ b/bin/propolis-server/src/main.rs @@ -122,6 +122,8 @@ fn run_server( ) -> anyhow::Result<()> { use propolis::api_version; + slog::info!(log, "Running {}", propolis::version()); + // Check that devices conform to expected API version if let Err(e) = api_version::check() { use api_version::{Error, VersionCheckError}; diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index cc9be47d9..608dabafd 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1625,6 +1625,8 @@ fn main() -> anyhow::Result { let log = build_log(log_level); + slog::info!(log, "Running {}", propolis::version()); + // Check that vmm and viona device version match what we expect api_version_checks(&log).context("API version checks")?; diff --git a/lib/propolis/src/lib.rs b/lib/propolis/src/lib.rs index ce9ae13ce..108bfed02 100644 --- a/lib/propolis/src/lib.rs +++ b/lib/propolis/src/lib.rs @@ -109,7 +109,8 @@ mod tests { fn print_version() { let v = version(); eprintln!("propolis {v}"); - assert!(version.contains(env!("CARGO_PKG_VERSION"))); - assert!(version.contains("Bhyve API")); + assert!(v.contains(env!("CARGO_PKG_VERSION"))); + assert!(v.contains("bhyve API")); + assert!(v.contains("viona API")); } } From eb888d170f980b455c2132e879782b7b2f02b2e6 Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 12 Aug 2026 02:04:52 +0000 Subject: [PATCH 3/4] ope errors are important too --- lib/propolis/src/lib.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/propolis/src/lib.rs b/lib/propolis/src/lib.rs index 108bfed02..e483e07be 100644 --- a/lib/propolis/src/lib.rs +++ b/lib/propolis/src/lib.rs @@ -76,22 +76,20 @@ pub fn version() -> &'static str { version.push_str(", "); match bhyve_api::api_version() { Ok(v) => { - write!(version, "bhyve API v{v}") - .expect("writing to a string never fails"); + write!(version, "bhyve API v{v}").unwrap(); } Err(_) => { - version.push_str(""); + version.push_str(""); } } version.push_str(", "); match viona_api::api_version() { Ok(v) => { - write!(version, "viona API v{v}") - .expect("writing to a string never fails"); + write!(version, "viona API v{v}").unwrap(); } Err(_) => { - version.push_str(""); + version.push_str(""); } } From b1b747df7844ed4d24a79206a7c8434ae0eda17b Mon Sep 17 00:00:00 2001 From: iximeow Date: Wed, 12 Aug 2026 02:23:46 +0000 Subject: [PATCH 4/4] i have literally never seen cargo xtask style before --- lib/propolis/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/propolis/src/lib.rs b/lib/propolis/src/lib.rs index e483e07be..663263458 100644 --- a/lib/propolis/src/lib.rs +++ b/lib/propolis/src/lib.rs @@ -100,7 +100,7 @@ pub fn version() -> &'static str { } #[cfg(test)] -mod tests { +mod test { use super::*; #[test]