From 3ad03a57f03ca004ddef5d582c7512f7e1858260 Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 7 May 2024 09:26:04 -0700 Subject: [PATCH 1/2] populate SMBIOS system version with Git metadata Currently, the SMBIOS system (type 1) table has a hard-coded version field. It would be nice if this was instead populated with details about the Propolis version, as described in issue #701. 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, as described in [this comment][2]. This is generated in a `propolis::version()` function, which also includes the Bhyve API version (detected at runtime). This results in version strings like: ``` Propolis v0.1.0-658 (0d8efa1) eliza/somebios-version, ``` (on a Linux machine; the Bhyve version would be present on illumos) In addition to populating the SMBIOS system version, this commit also sets the Clap version for CLI commands, so that the `--version` flag will print out the same value that's set in SMBIOS. [1]: https://docs.rs/vergen [2]: https://github.com/oxidecomputer/propolis/issues/701#issuecomment-2096755479 --- Cargo.lock | 1 + Cargo.toml | 1 + bin/propolis-server/src/main.rs | 2 +- bin/propolis-standalone/src/main.rs | 1 + lib/propolis/Cargo.toml | 4 +++ lib/propolis/build.rs | 16 +++++++++ lib/propolis/src/firmware/smbios/table.rs | 18 +++++++++- lib/propolis/src/lib.rs | 43 +++++++++++++++++++++++ 8 files changed, 84 insertions(+), 2 deletions(-) create mode 100644 lib/propolis/build.rs diff --git a/Cargo.lock b/Cargo.lock index f4c16a80e..ac2316064 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3814,6 +3814,7 @@ dependencies = [ "tokio", "usdt 0.5.0", "uuid 1.8.0", + "vergen", "viona_api", ] diff --git a/Cargo.toml b/Cargo.toml index e22291cd1..5a064e1eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -160,3 +160,4 @@ tracing-bunyan-formatter = "0.3.3" tracing-subscriber = "0.3.14" usdt = { version = "0.5", default-features = false } uuid = "1.3.2" +vergen = { version = "8.0.0", features = ["git", "gitcl"]} diff --git a/bin/propolis-server/src/main.rs b/bin/propolis-server/src/main.rs index 8f14a676c..78a3ad8f4 100644 --- a/bin/propolis-server/src/main.rs +++ b/bin/propolis-server/src/main.rs @@ -19,7 +19,7 @@ use propolis_server::{ }; #[derive(Debug, Parser)] -#[clap(about, version)] +#[clap(about, version = propolis::version())] /// An HTTP server providing access to Propolis enum Args { /// Generates the OpenAPI specification. diff --git a/bin/propolis-standalone/src/main.rs b/bin/propolis-standalone/src/main.rs index ee0b76803..910a098a5 100644 --- a/bin/propolis-standalone/src/main.rs +++ b/bin/propolis-standalone/src/main.rs @@ -1281,6 +1281,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 5077cce59..f6c996db0 100644 --- a/lib/propolis/Cargo.toml +++ b/lib/propolis/Cargo.toml @@ -43,6 +43,10 @@ rand = { workspace = true, optional = true } softnpu-lib = { workspace = true, optional = true } dlpi = { workspace = true, optional = true } +[build-dependencies] +anyhow.workspace = true +vergen.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..3e4018976 --- /dev/null +++ b/lib/propolis/build.rs @@ -0,0 +1,16 @@ +// 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<()> { + // Generate Git version information. + vergen::EmitBuilder::builder() + // Don't emit timestamps and build info. + .idempotent() + .git_branch() + .git_sha(true) + .git_commit_count() + .emit()?; + + Ok(()) +} diff --git a/lib/propolis/src/firmware/smbios/table.rs b/lib/propolis/src/firmware/smbios/table.rs index ad49a999e..9926a581d 100644 --- a/lib/propolis/src/firmware/smbios/table.rs +++ b/lib/propolis/src/firmware/smbios/table.rs @@ -351,7 +351,7 @@ pub mod type0 { BiosExtCharacteristics => u16, } } -#[derive(Default)] + pub struct Type1 { pub manufacturer: SmbString, pub product_name: SmbString, @@ -381,6 +381,22 @@ impl Table for Type1 { } } +impl Default for Type1 { + fn default() -> Self { + Type1 { + manufacturer: SmbString::default(), + product_name: SmbString::default(), + version: SmbString::try_from(crate::version()) + .expect("version string should not contain NULs"), + serial_number: SmbString::default(), + uuid: [0; 16], + wake_up_type: type1::WakeUpType::default(), + sku_number: SmbString::default(), + family: SmbString::default(), + } + } +} + pub mod type1 { use super::*; diff --git a/lib/propolis/src/lib.rs b/lib/propolis/src/lib.rs index 22812a988..4115200cf 100644 --- a/lib/propolis/src/lib.rs +++ b/lib/propolis/src/lib.rs @@ -35,3 +35,46 @@ pub mod vmm; 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 = option_env!("VERGEN_GIT_BRANCH") + .and_then(|branch| Some((branch, option_env!("VERGEN_GIT_SHA")?))) + .and_then(|(branch, sha)| Some((branch, sha, option_env!("VERGEN_GIT_COMMIT_COUNT")?))); + + let mut version = format!("Propolis v{}", env!("CARGO_PKG_VERSION")); + if let Some((branch, sha, commit)) = git { + write!(version, "-{commit} ({sha}) {branch}, ") + .expect("writing to a string never fails"); + } else { + 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 + }; + }; + &VERSION +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn print_version() { + let v = version(); + eprintln!("version: {v}"); + assert!(v.starts_with("Propolis v")); + } +} From 934eb946cb29f1680778a9a6ff23bf2acf44b41c Mon Sep 17 00:00:00 2001 From: Eliza Weisman Date: Tue, 7 May 2024 11:47:39 -0700 Subject: [PATCH 2/2] remove prefix --- lib/propolis/src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/propolis/src/lib.rs b/lib/propolis/src/lib.rs index 4115200cf..e26d4e5d6 100644 --- a/lib/propolis/src/lib.rs +++ b/lib/propolis/src/lib.rs @@ -45,7 +45,7 @@ pub fn version() -> &'static str { .and_then(|branch| Some((branch, option_env!("VERGEN_GIT_SHA")?))) .and_then(|(branch, sha)| Some((branch, sha, option_env!("VERGEN_GIT_COMMIT_COUNT")?))); - let mut version = format!("Propolis v{}", env!("CARGO_PKG_VERSION")); + let mut version = format!("v{}", env!("CARGO_PKG_VERSION")); if let Some((branch, sha, commit)) = git { write!(version, "-{commit} ({sha}) {branch}, ") .expect("writing to a string never fails"); @@ -74,7 +74,8 @@ mod tests { #[test] fn print_version() { let v = version(); - eprintln!("version: {v}"); - assert!(v.starts_with("Propolis v")); + eprintln!("propolis {v}"); + assert!(version.contains(env!("CARGO_PKG_VERSION"))); + assert!(version.contains("Bhyve API")); } }