diff --git a/bin/propolis-server/src/lib/spec/api_spec_latest.rs b/bin/propolis-server/src/lib/spec/api_spec_latest.rs index b3772e5ec..2af35d8a3 100644 --- a/bin/propolis-server/src/lib/spec/api_spec_latest.rs +++ b/bin/propolis-server/src/lib/spec/api_spec_latest.rs @@ -38,6 +38,11 @@ pub(crate) fn latest_to_spec_builder( value: latest::instance_spec::InstanceSpec, ) -> Result { let mut builder = SpecBuilder::with_instance_spec_board(value.board)?; + + if let Some(smbios) = value.smbios { + builder.set_smbios_type1_input(smbios); + } + let mut devices: Vec<(SpecKey, latest::instance_spec::Component)> = vec![]; let mut boot_settings = None; let mut storage_backends: BTreeMap = @@ -216,3 +221,49 @@ pub(crate) fn latest_to_spec_builder( Ok(builder) } + +#[cfg(test)] +mod test { + use super::*; + use latest::components::board::{ + Board, Chipset, Cpuid, GuestHypervisorInterface, I440Fx, + }; + use latest::instance_spec::{CpuidVendor, SmbiosType1Input}; + + // Regression test: the SMBIOS type 1 input must survive conversion + // from the API instance spec to the internal spec. The conversion rework in + // #1178 dropped it, leaving guests with default type 1 contents. + #[test] + fn smbios_type1_input_preserved() { + let api_spec = latest::instance_spec::InstanceSpec { + board: Board { + cpus: 4, + memory_mb: 512, + chipset: Chipset::I440Fx(I440Fx { enable_pcie: false }), + guest_hv_interface: GuestHypervisorInterface::Bhyve, + // Explicit values keep the builder from querying bhyve for + // its default guest CPUID set, which needs VMM device access + // the test runner may lack. + cpuid: Some(Cpuid { + entries: vec![], + vendor: CpuidVendor::Amd, + }), + }, + components: Default::default(), + smbios: Some(SmbiosType1Input { + manufacturer: "a4x2".to_string(), + product_name: "913-0000019".to_string(), + serial_number: "2FAKE000".to_string(), + version: 2, + }), + }; + + let spec = latest_to_spec_builder(api_spec).unwrap().finish(); + let smbios = + spec.smbios_type1_input.expect("SMBIOS type 1 input preserved"); + assert_eq!(smbios.manufacturer, "a4x2"); + assert_eq!(smbios.product_name, "913-0000019"); + assert_eq!(smbios.serial_number, "2FAKE000"); + assert_eq!(smbios.version, 2); + } +} diff --git a/bin/propolis-server/src/lib/spec/builder.rs b/bin/propolis-server/src/lib/spec/builder.rs index 78560da8e..e3290369e 100644 --- a/bin/propolis-server/src/lib/spec/builder.rs +++ b/bin/propolis-server/src/lib/spec/builder.rs @@ -11,7 +11,7 @@ use propolis_api_types::instance_spec::{ board::Board as InstanceSpecBoard, devices::{PciPciBridge, SerialPortNumber}, }, - PciPath, SpecKey, + PciPath, SmbiosType1Input, SpecKey, }; use thiserror::Error; @@ -391,6 +391,11 @@ impl SpecBuilder { Ok(self) } + /// Sets the SMBIOS type 1 table contents to expose to the guest. + pub fn set_smbios_type1_input(&mut self, input: SmbiosType1Input) { + self.spec.smbios_type1_input = Some(input); + } + /// Yields the completed spec, consuming the builder. pub fn finish(self) -> super::Spec { self.spec