From 9b6ad47478dca2c501e941a30fdbece07a40638a Mon Sep 17 00:00:00 2001 From: Greg Colombo Date: Fri, 18 Apr 2025 16:35:58 +0000 Subject: [PATCH 1/5] try using the native types in the API instead This might make things somewhat nicer when sled-agent re-exports these. --- bin/propolis-cli/src/main.rs | 37 ++++++++++++------- .../src/instance_spec/components/board.rs | 6 +++ .../src/instance_spec/mod.rs | 10 ++++- crates/propolis-config-toml/src/spec.rs | 11 +++--- lib/propolis-client/src/lib.rs | 30 +++++++++++++-- phd-tests/framework/src/disk/crucible.rs | 2 +- phd-tests/framework/src/disk/file.rs | 2 +- phd-tests/framework/src/disk/in_memory.rs | 2 +- phd-tests/framework/src/disk/mod.rs | 2 +- phd-tests/framework/src/test_vm/config.rs | 28 ++++++++------ phd-tests/framework/src/test_vm/mod.rs | 9 +++-- phd-tests/framework/src/test_vm/spec.rs | 13 +++++-- phd-tests/tests/src/cpuid.rs | 5 ++- phd-tests/tests/src/hyperv.rs | 36 ++++++++---------- phd-tests/tests/src/smoke.rs | 4 +- phd-tests/tests/src/stats.rs | 6 +-- 16 files changed, 128 insertions(+), 75 deletions(-) diff --git a/bin/propolis-cli/src/main.rs b/bin/propolis-cli/src/main.rs index e05186022..346bc4a58 100644 --- a/bin/propolis-cli/src/main.rs +++ b/bin/propolis-cli/src/main.rs @@ -16,15 +16,17 @@ use anyhow::{anyhow, Context}; use clap::{Args, Parser, Subcommand}; use futures::{future, SinkExt}; use newtype_uuid::{GenericUuid, TypedUuid, TypedUuidKind, TypedUuidTag}; -use propolis_client::support::nvme_serial_from_str; -use propolis_client::types::{ +use propolis_client::instance_spec::{ BlobStorageBackend, Board, Chipset, ComponentV0, CrucibleStorageBackend, - GuestHypervisorInterface, HyperVFeatureFlag, I440Fx, InstanceEnsureRequest, - InstanceInitializationMethod, InstanceMetadata, InstanceSpecGetResponse, - InstanceSpecV0, NvmeDisk, QemuPvpanic, ReplacementComponent, SerialPort, + GuestHypervisorInterface, HyperVFeatureFlag, I440Fx, InstanceSpecV0, + NvmeDisk, PciPath, QemuPvpanic, ReplacementComponent, SerialPort, SerialPortNumber, SpecKey, VirtioDisk, }; -use propolis_client::PciPath; +use propolis_client::support::nvme_serial_from_str; +use propolis_client::types::{ + InstanceEnsureRequest, InstanceInitializationMethod, InstanceMetadata, + InstanceSpecGetResponse, +}; use propolis_config_toml::spec::SpecConfig; use serde::{Deserialize, Serialize}; use slog::{o, Drain, Level, Logger}; @@ -200,10 +202,17 @@ fn add_component_to_spec( id: SpecKey, component: ComponentV0, ) -> anyhow::Result<()> { - if spec.components.insert(id.to_string(), component).is_some() { - anyhow::bail!("duplicate component ID {id:?}"); + use std::collections::btree_map::Entry; + match spec.components.entry(id) { + Entry::Vacant(vacant_entry) => { + vacant_entry.insert(component); + Ok(()) + } + Entry::Occupied(occupied_entry) => Err(anyhow::anyhow!( + "duplicate component ID {:?}", + occupied_entry.key() + )), } - Ok(()) } /// A legacy Propolis API disk request, preserved here for compatibility with @@ -298,11 +307,13 @@ impl VmConfig { cpus: self.vcpus, memory_mb: self.memory, guest_hv_interface: if self.hyperv { - Some(GuestHypervisorInterface::HyperV { - features: vec![HyperVFeatureFlag::ReferenceTsc], - }) + GuestHypervisorInterface::HyperV { + features: [HyperVFeatureFlag::ReferenceTsc] + .into_iter() + .collect(), + } } else { - None + Default::default() }, }, components: Default::default(), diff --git a/crates/propolis-api-types/src/instance_spec/components/board.rs b/crates/propolis-api-types/src/instance_spec/components/board.rs index d04973b35..9295296e6 100644 --- a/crates/propolis-api-types/src/instance_spec/components/board.rs +++ b/crates/propolis-api-types/src/instance_spec/components/board.rs @@ -38,6 +38,12 @@ pub enum Chipset { I440Fx(I440Fx), } +impl Default for Chipset { + fn default() -> Self { + Self::I440Fx(I440Fx { enable_pcie: false }) + } +} + /// A set of CPUID values to expose to a guest. #[derive(Clone, Deserialize, Serialize, Debug, JsonSchema)] #[serde(deny_unknown_fields)] diff --git a/crates/propolis-api-types/src/instance_spec/mod.rs b/crates/propolis-api-types/src/instance_spec/mod.rs index 3742b6493..a7254a256 100644 --- a/crates/propolis-api-types/src/instance_spec/mod.rs +++ b/crates/propolis-api-types/src/instance_spec/mod.rs @@ -217,10 +217,16 @@ impl std::fmt::Display for SpecKey { impl std::str::FromStr for SpecKey { type Err = core::convert::Infallible; fn from_str(s: &str) -> Result { - Ok(match Uuid::parse_str(s) { + Ok(s.into()) + } +} + +impl From<&str> for SpecKey { + fn from(s: &str) -> Self { + match Uuid::parse_str(s) { Ok(uuid) => Self::Uuid(uuid), Err(_) => Self::Name(s.to_owned()), - }) + } } } diff --git a/crates/propolis-config-toml/src/spec.rs b/crates/propolis-config-toml/src/spec.rs index f9fdd897c..a4306c7d1 100644 --- a/crates/propolis-config-toml/src/spec.rs +++ b/crates/propolis-config-toml/src/spec.rs @@ -10,14 +10,13 @@ use std::{ }; use propolis_client::{ - support::nvme_serial_from_str, - types::{ + instance_spec::{ ComponentV0, DlpiNetworkBackend, FileStorageBackend, - MigrationFailureInjector, NvmeDisk, P9fs, PciPciBridge, SoftNpuP9, - SoftNpuPciPort, SoftNpuPort, SpecKey, VirtioDisk, VirtioNetworkBackend, - VirtioNic, + MigrationFailureInjector, NvmeDisk, P9fs, PciPath, PciPciBridge, + SoftNpuP9, SoftNpuPciPort, SoftNpuPort, SpecKey, VirtioDisk, + VirtioNetworkBackend, VirtioNic, }, - PciPath, + support::nvme_serial_from_str, }; use thiserror::Error; diff --git a/lib/propolis-client/src/lib.rs b/lib/propolis-client/src/lib.rs index e2a946296..03fd7e5eb 100644 --- a/lib/propolis-client/src/lib.rs +++ b/lib/propolis-client/src/lib.rs @@ -4,9 +4,28 @@ //! A client for the Propolis hypervisor frontend's server API. -// Re-export types from propolis_api_types where callers may want to use -// constructors or From impls. -pub use propolis_api_types::instance_spec::{PciPath, SpecKey}; +/// Re-exports of types related to instance specs. +/// +/// These types are re-exported for the convenience of components like +/// sled-agent that may wish to expose instance specs in their own APIs. +/// Defining the sled-agent API in terms of these "native" types allows +/// sled-agent to reuse their trait implementations (and in particular use +/// "manual" impls of things that Progenitor would otherwise derive). +/// +/// In the generated client, the native "top-level" instance spec and component +/// types ([`VersionedInstanceSpec`], [`InstanceSpecV0`], and +/// [`ReplacementComponent`]) replace their generated counterparts. This +/// obviates the need to maintain `From` impls to convert between native and +/// generated types. +pub mod instance_spec { + pub use propolis_api_types::instance_spec::{ + components::{backends::*, board::*, devices::*}, + v0::*, + *, + }; + + pub use propolis_api_types::ReplacementComponent; +} // Re-export Crucible client types that appear in their serialized forms in // instance specs. This allows clients to ensure they serialize/deserialize @@ -19,7 +38,10 @@ progenitor::generate_api!( interface = Builder, tags = Separate, replace = { - PciPath = crate::PciPath, + PciPath = crate::instance_spec::PciPath, + ReplacementComponent = crate::instance_spec::ReplacementComponent, + InstanceSpecV0 = crate::instance_spec::InstanceSpecV0, + VersionedInstanceSpec = crate::instance_spec::VersionedInstanceSpec, }, // Automatically derive JsonSchema for instance spec-related types so that // they can be reused in sled-agent's API. This can't be done with a diff --git a/phd-tests/framework/src/disk/crucible.rs b/phd-tests/framework/src/disk/crucible.rs index d75eb915e..a00daa2b1 100644 --- a/phd-tests/framework/src/disk/crucible.rs +++ b/phd-tests/framework/src/disk/crucible.rs @@ -13,7 +13,7 @@ use std::{ use anyhow::Context; use propolis_client::{ - types::{ComponentV0, CrucibleStorageBackend}, + instance_spec::{ComponentV0, CrucibleStorageBackend}, CrucibleOpts, VolumeConstructionRequest, }; use rand::{rngs::StdRng, RngCore, SeedableRng}; diff --git a/phd-tests/framework/src/disk/file.rs b/phd-tests/framework/src/disk/file.rs index 294c4c76c..3791522ba 100644 --- a/phd-tests/framework/src/disk/file.rs +++ b/phd-tests/framework/src/disk/file.rs @@ -5,7 +5,7 @@ //! Abstractions for disks with a raw file backend. use camino::{Utf8Path, Utf8PathBuf}; -use propolis_client::types::{ComponentV0, FileStorageBackend}; +use propolis_client::instance_spec::{ComponentV0, FileStorageBackend}; use tracing::{debug, error, warn}; use uuid::Uuid; diff --git a/phd-tests/framework/src/disk/in_memory.rs b/phd-tests/framework/src/disk/in_memory.rs index 44bc6cd1f..1218f326f 100644 --- a/phd-tests/framework/src/disk/in_memory.rs +++ b/phd-tests/framework/src/disk/in_memory.rs @@ -4,7 +4,7 @@ //! Abstractions for disks with an in-memory backend. -use propolis_client::types::{BlobStorageBackend, ComponentV0}; +use propolis_client::instance_spec::{BlobStorageBackend, ComponentV0}; use super::DiskConfig; use crate::disk::DeviceName; diff --git a/phd-tests/framework/src/disk/mod.rs b/phd-tests/framework/src/disk/mod.rs index 21ff8b339..2219a3b06 100644 --- a/phd-tests/framework/src/disk/mod.rs +++ b/phd-tests/framework/src/disk/mod.rs @@ -13,7 +13,7 @@ use std::sync::Arc; use anyhow::Context; use camino::{Utf8Path, Utf8PathBuf}; use in_memory::InMemoryDisk; -use propolis_client::types::ComponentV0; +use propolis_client::instance_spec::ComponentV0; use thiserror::Error; use crate::{ diff --git a/phd-tests/framework/src/test_vm/config.rs b/phd-tests/framework/src/test_vm/config.rs index ca08b6d4d..a6653e805 100644 --- a/phd-tests/framework/src/test_vm/config.rs +++ b/phd-tests/framework/src/test_vm/config.rs @@ -7,14 +7,14 @@ use std::sync::Arc; use anyhow::Context; use cpuid_utils::CpuidIdent; use propolis_client::{ - support::nvme_serial_from_str, - types::{ + instance_spec::{ Board, BootOrderEntry, BootSettings, Chipset, ComponentV0, Cpuid, - CpuidEntry, CpuidVendor, GuestHypervisorInterface, InstanceMetadata, - InstanceSpecV0, MigrationFailureInjector, NvmeDisk, SerialPort, + CpuidEntry, CpuidVendor, GuestHypervisorInterface, InstanceSpecV0, + MigrationFailureInjector, NvmeDisk, PciPath, SerialPort, SerialPortNumber, SpecKey, VirtioDisk, }, - PciPath, + support::nvme_serial_from_str, + types::InstanceMetadata, }; use uuid::Uuid; @@ -299,7 +299,10 @@ impl<'dr> VmConfig<'dr> { cpuid_utils::CpuidVendor::Intel => CpuidVendor::Intel, }, }), - guest_hv_interface: guest_hv_interface.clone(), + guest_hv_interface: guest_hv_interface + .as_ref() + .cloned() + .unwrap_or_default(), }, components: Default::default(), }; @@ -338,24 +341,25 @@ impl<'dr> VmConfig<'dr> { }), }; - let _old = - spec.components.insert(device_name.into_string(), device_spec); + let _old = spec + .components + .insert(device_name.into_string().into(), device_spec); assert!(_old.is_none()); let _old = spec .components - .insert(backend_name.into_string(), backend_spec); + .insert(backend_name.into_string().into(), backend_spec); assert!(_old.is_none()); } let _old = spec.components.insert( - "com1".to_string(), + "com1".into(), ComponentV0::SerialPort(SerialPort { num: SerialPortNumber::Com1 }), ); assert!(_old.is_none()); if let Some(boot_order) = boot_order.as_ref() { let _old = spec.components.insert( - "boot-settings".to_string(), + "boot-settings".into(), ComponentV0::BootSettings(BootSettings { order: boot_order .iter() @@ -370,7 +374,7 @@ impl<'dr> VmConfig<'dr> { if let Some(mig) = migration_failure.as_ref() { let _old = spec.components.insert( - "migration-failure".to_string(), + "migration-failure".into(), ComponentV0::MigrationFailureInjector(mig.clone()), ); assert!(_old.is_none()); diff --git a/phd-tests/framework/src/test_vm/mod.rs b/phd-tests/framework/src/test_vm/mod.rs index 3b16bd982..b01ef01f1 100644 --- a/phd-tests/framework/src/test_vm/mod.rs +++ b/phd-tests/framework/src/test_vm/mod.rs @@ -27,13 +27,14 @@ use anyhow::{anyhow, Context, Result}; use camino::Utf8PathBuf; use core::result::Result as StdResult; use propolis_client::{ + instance_spec::{ComponentV0, ReplacementComponent}, support::{InstanceSerialConsoleHelper, WSClientOffset}, types::{ - ComponentV0, InstanceEnsureRequest, InstanceGetResponse, + InstanceEnsureRequest, InstanceGetResponse, InstanceInitializationMethod, InstanceMigrateStatusResponse, InstanceProperties, InstanceSerialConsoleHistoryResponse, InstanceSpecGetResponse, InstanceState, InstanceStateRequested, - MigrationState, ReplacementComponent, + MigrationState, }, }; use propolis_client::{Client, ResponseValue}; @@ -601,7 +602,7 @@ impl TestVm { match comp { ComponentV0::MigrationFailureInjector(inj) => { map.insert( - id.clone(), + id.to_string(), ReplacementComponent::MigrationFailureInjector( inj.clone(), ), @@ -609,7 +610,7 @@ impl TestVm { } ComponentV0::CrucibleStorageBackend(be) => { map.insert( - id.clone(), + id.to_string(), ReplacementComponent::CrucibleStorageBackend( be.clone(), ), diff --git a/phd-tests/framework/src/test_vm/spec.rs b/phd-tests/framework/src/test_vm/spec.rs index d0ef3f8c5..32c11acc3 100644 --- a/phd-tests/framework/src/test_vm/spec.rs +++ b/phd-tests/framework/src/test_vm/spec.rs @@ -9,7 +9,10 @@ use crate::{ guest_os::GuestOsKind, }; use camino::Utf8PathBuf; -use propolis_client::types::{ComponentV0, InstanceMetadata, InstanceSpecV0}; +use propolis_client::{ + instance_spec::{ComponentV0, InstanceSpecV0}, + types::InstanceMetadata, +}; use uuid::Uuid; /// The set of objects needed to start and run a guest in a `TestVm`. @@ -82,8 +85,12 @@ impl VmSpec { }; let backend_spec = disk.backend_spec(); - let backend_name = - disk.device_name().clone().into_backend_name().into_string(); + let backend_name = disk + .device_name() + .clone() + .into_backend_name() + .into_string() + .into(); if let Some(ComponentV0::CrucibleStorageBackend(_)) = spec.components.get(&backend_name) { diff --git a/phd-tests/tests/src/cpuid.rs b/phd-tests/tests/src/cpuid.rs index b05081640..ead1613a3 100644 --- a/phd-tests/tests/src/cpuid.rs +++ b/phd-tests/tests/src/cpuid.rs @@ -5,8 +5,9 @@ use cpuid_utils::{CpuidIdent, CpuidSet, CpuidValues}; use phd_framework::{test_vm::MigrationTimeout, TestVm}; use phd_testcase::*; -use propolis_client::types::{ - CpuidEntry, InstanceSpecStatus, VersionedInstanceSpec, +use propolis_client::{ + instance_spec::{CpuidEntry, VersionedInstanceSpec}, + types::InstanceSpecStatus, }; use tracing::info; use uuid::Uuid; diff --git a/phd-tests/tests/src/hyperv.rs b/phd-tests/tests/src/hyperv.rs index a54a71af0..e4f4db80c 100644 --- a/phd-tests/tests/src/hyperv.rs +++ b/phd-tests/tests/src/hyperv.rs @@ -8,7 +8,9 @@ use phd_framework::{ artifacts, lifecycle::Action, test_vm::MigrationTimeout, TestVm, }; use phd_testcase::*; -use propolis_client::types::HyperVFeatureFlag; +use propolis_client::instance_spec::{ + GuestHypervisorInterface, HyperVFeatureFlag, +}; use tracing::{info, warn}; use uuid::Uuid; @@ -51,11 +53,9 @@ async fn guest_detect_hyperv(vm: &TestVm) -> anyhow::Result<()> { #[phd_testcase] async fn hyperv_smoke_test(ctx: &Framework) { let mut cfg = ctx.vm_config_builder("hyperv_smoke_test"); - cfg.guest_hv_interface( - propolis_client::types::GuestHypervisorInterface::HyperV { - features: vec![], - }, - ); + cfg.guest_hv_interface(GuestHypervisorInterface::HyperV { + features: Default::default(), + }); let mut vm = ctx.spawn_vm(&cfg, None).await?; vm.launch().await?; vm.wait_to_boot().await?; @@ -66,11 +66,9 @@ async fn hyperv_smoke_test(ctx: &Framework) { #[phd_testcase] async fn hyperv_lifecycle_test(ctx: &Framework) { let mut cfg = ctx.vm_config_builder("hyperv_lifecycle_test"); - cfg.guest_hv_interface( - propolis_client::types::GuestHypervisorInterface::HyperV { - features: vec![], - }, - ); + cfg.guest_hv_interface(GuestHypervisorInterface::HyperV { + features: Default::default(), + }); let mut vm = ctx.spawn_vm(&cfg, None).await?; vm.launch().await?; vm.wait_to_boot().await?; @@ -93,11 +91,9 @@ async fn hyperv_lifecycle_test(ctx: &Framework) { #[phd_testcase] async fn hyperv_reference_tsc_clocksource_test(ctx: &Framework) { let mut cfg = ctx.vm_config_builder("hyperv_reference_tsc_test"); - cfg.guest_hv_interface( - propolis_client::types::GuestHypervisorInterface::HyperV { - features: vec![HyperVFeatureFlag::ReferenceTsc], - }, - ); + cfg.guest_hv_interface(GuestHypervisorInterface::HyperV { + features: [HyperVFeatureFlag::ReferenceTsc].into_iter().collect(), + }); let mut vm = ctx.spawn_vm(&cfg, None).await?; vm.launch().await?; vm.wait_to_boot().await?; @@ -281,11 +277,9 @@ async fn hyperv_reference_tsc_elapsed_time_test(ctx: &Framework) { } let mut cfg = ctx.vm_config_builder("hyperv_reference_tsc_elapsed_test"); - cfg.guest_hv_interface( - propolis_client::types::GuestHypervisorInterface::HyperV { - features: vec![HyperVFeatureFlag::ReferenceTsc], - }, - ); + cfg.guest_hv_interface(GuestHypervisorInterface::HyperV { + features: [HyperVFeatureFlag::ReferenceTsc].into_iter().collect(), + }); let mut vm = ctx.spawn_vm(&cfg, None).await?; vm.launch().await?; vm.wait_to_boot().await?; diff --git a/phd-tests/tests/src/smoke.rs b/phd-tests/tests/src/smoke.rs index b3a14d3d4..abd498375 100644 --- a/phd-tests/tests/src/smoke.rs +++ b/phd-tests/tests/src/smoke.rs @@ -3,7 +3,9 @@ // file, You can obtain one at https://mozilla.org/MPL/2.0/. use phd_testcase::*; -use propolis_client::types::{InstanceSpecStatus, VersionedInstanceSpec}; +use propolis_client::{ + instance_spec::VersionedInstanceSpec, types::InstanceSpecStatus, +}; #[phd_testcase] async fn nproc_test(ctx: &Framework) { diff --git a/phd-tests/tests/src/stats.rs b/phd-tests/tests/src/stats.rs index f7a962e4b..a472a4aea 100644 --- a/phd-tests/tests/src/stats.rs +++ b/phd-tests/tests/src/stats.rs @@ -7,7 +7,7 @@ use std::str::FromStr; use std::time::Duration; use phd_framework::test_vm::{FakeOximeterSampler, MetricsLocation}; -use propolis_client::types::HyperVFeatureFlag; +use propolis_client::instance_spec::HyperVFeatureFlag; use chrono::{DateTime, Utc}; use oximeter::types::{ProducerResults, ProducerResultsItem, Sample}; @@ -217,8 +217,8 @@ async fn instance_vcpu_stats(ctx: &Framework) { let mut vm_config = ctx.vm_config_builder("instance_vcpu_stats"); vm_config.guest_hv_interface( - propolis_client::types::GuestHypervisorInterface::HyperV { - features: vec![HyperVFeatureFlag::ReferenceTsc], + propolis_client::instance_spec::GuestHypervisorInterface::HyperV { + features: [HyperVFeatureFlag::ReferenceTsc].into_iter().collect(), }, ); // Having one CPU simplifies the math for time expectations later in the From 308b74e3aad0c138b360640f4acc900d4c51e9e3 Mon Sep 17 00:00:00 2001 From: Greg Colombo Date: Fri, 18 Apr 2025 17:02:39 +0000 Subject: [PATCH 2/5] IT LOOKS LIKE YOU'RE CASTING AN INTEGER WOULD YOU LIKE HELP --- lib/propolis/src/block/file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/propolis/src/block/file.rs b/lib/propolis/src/block/file.rs index feb034ea5..4d65d446f 100644 --- a/lib/propolis/src/block/file.rs +++ b/lib/propolis/src/block/file.rs @@ -409,7 +409,7 @@ mod dkioc { } DiscardMech::FnctlFreesp => { let mut fl = libc::flock { - l_type: libc::F_WRLCK as i16, + l_type: libc::F_WRLCK, l_whence: 0, l_start: off as i64, l_len: len as i64, From d49feefb8554da6229ab32a0dc0f3cb7f9602f3b Mon Sep 17 00:00:00 2001 From: Greg Colombo Date: Fri, 18 Apr 2025 17:02:39 +0000 Subject: [PATCH 3/5] remove unneeded JsonSchema impls for generated types --- lib/propolis-client/src/lib.rs | 92 +--------------------------------- 1 file changed, 2 insertions(+), 90 deletions(-) diff --git a/lib/propolis-client/src/lib.rs b/lib/propolis-client/src/lib.rs index 03fd7e5eb..b2c186b4f 100644 --- a/lib/propolis-client/src/lib.rs +++ b/lib/propolis-client/src/lib.rs @@ -48,99 +48,11 @@ progenitor::generate_api!( // `derives = [schemars::JsonSchema]` directive because the `SpecKey` type // needs to implement that trait manually (see below). patch = { - BlobStorageBackend = { derives = [ schemars::JsonSchema ]}, - Board = { derives = [ schemars::JsonSchema ]}, - BootOrderEntry = { derives = [ schemars::JsonSchema ]}, - BootSettings = { derives = [ schemars::JsonSchema, Default] }, - ComponentV0 = { derives = [ schemars::JsonSchema ]}, - Chipset = { derives = [ schemars::JsonSchema ]}, - CrucibleStorageBackend = { derives = [ schemars::JsonSchema ]}, - Cpuid = { derives = [ schemars::JsonSchema ]}, - CpuidEntry = { derives = [ schemars::JsonSchema, PartialEq, Eq, Copy ]}, - CpuidVendor = { derives = [ schemars::JsonSchema ]}, - DlpiNetworkBackend = { derives = [ schemars::JsonSchema ]}, - FileStorageBackend = { derives = [ schemars::JsonSchema ]}, - GuestHypervisorInterface = { derives = [ schemars::JsonSchema ]}, - I440Fx = { derives = [ schemars::JsonSchema ]}, - HyperVFeatureFlag = { derives = [ schemars::JsonSchema ]}, - MigrationFailureInjector = { derives = [ schemars::JsonSchema ]}, - NvmeDisk = { derives = [ schemars::JsonSchema ]}, + BootSettings = { derives = [ Default] }, + CpuidEntry = { derives = [ PartialEq, Eq, Copy ]}, InstanceMetadata = { derives = [ PartialEq ] }, - InstanceSpecV0 = { derives = [ schemars::JsonSchema ]}, - PciPciBridge = { derives = [ schemars::JsonSchema ]}, - P9fs = { derives = [ schemars::JsonSchema ]}, - QemuPvpanic = { derives = [ schemars::JsonSchema ]}, - SerialPort = { derives = [ schemars::JsonSchema ]}, - SerialPortNumber = { derives = [ schemars::JsonSchema ]}, - SoftNpuP9 = { derives = [ schemars::JsonSchema ]}, - SoftNpuPort = { derives = [ schemars::JsonSchema ]}, - SoftNpuPciPort = { derives = [ schemars::JsonSchema ]}, SpecKey = { derives = [ PartialEq, Eq, Ord, PartialOrd, Hash ] }, - VirtioDisk = { derives = [ schemars::JsonSchema ]}, - VirtioNic = { derives = [ schemars::JsonSchema ]}, - VirtioNetworkBackend = { derives = [ schemars::JsonSchema ]}, } ); -// Supply the same JsonSchema implementation for the generated SpecKey type that -// the native type has. This allows sled-agent (or another consumer) to reuse -// the generated type in its own API to produce an API document that generates -// the correct type for sled-agent's (or the other consumer's) clients. -impl schemars::JsonSchema for types::SpecKey { - fn schema_name() -> String { - "SpecKey".to_owned() - } - - fn json_schema( - generator: &mut schemars::gen::SchemaGenerator, - ) -> schemars::schema::Schema { - use schemars::schema::*; - fn label_schema(label: &str, schema: Schema) -> Schema { - SchemaObject { - metadata: Some( - Metadata { - title: Some(label.to_string()), - ..Default::default() - } - .into(), - ), - subschemas: Some( - SubschemaValidation { - all_of: Some(vec![schema]), - ..Default::default() - } - .into(), - ), - ..Default::default() - } - .into() - } - - SchemaObject { - metadata: Some( - Metadata { - description: Some( - "A key identifying a component in an instance spec." - .to_string(), - ), - ..Default::default() - } - .into(), - ), - subschemas: Some(Box::new(SubschemaValidation { - one_of: Some(vec![ - label_schema( - "uuid", - generator.subschema_for::(), - ), - label_schema("name", generator.subschema_for::()), - ]), - ..Default::default() - })), - ..Default::default() - } - .into() - } -} - pub mod support; From ffeb813bd137487ab5e942a91fea0a3c5469266e Mon Sep 17 00:00:00 2001 From: Greg Colombo Date: Fri, 18 Apr 2025 21:15:20 +0000 Subject: [PATCH 4/5] add back load-bearing cast --- lib/propolis/src/block/file.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/propolis/src/block/file.rs b/lib/propolis/src/block/file.rs index 4d65d446f..feb034ea5 100644 --- a/lib/propolis/src/block/file.rs +++ b/lib/propolis/src/block/file.rs @@ -409,7 +409,7 @@ mod dkioc { } DiscardMech::FnctlFreesp => { let mut fl = libc::flock { - l_type: libc::F_WRLCK, + l_type: libc::F_WRLCK as i16, l_whence: 0, l_start: off as i64, l_len: len as i64, From 674478287c93cd583e737b3c4ba9f25c6e9aa881 Mon Sep 17 00:00:00 2001 From: Greg Colombo Date: Mon, 28 Apr 2025 09:31:13 -0700 Subject: [PATCH 5/5] standardize whitespace Co-authored-by: Eliza Weisman --- lib/propolis-client/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/propolis-client/src/lib.rs b/lib/propolis-client/src/lib.rs index b2c186b4f..a562fc9e5 100644 --- a/lib/propolis-client/src/lib.rs +++ b/lib/propolis-client/src/lib.rs @@ -48,8 +48,8 @@ progenitor::generate_api!( // `derives = [schemars::JsonSchema]` directive because the `SpecKey` type // needs to implement that trait manually (see below). patch = { - BootSettings = { derives = [ Default] }, - CpuidEntry = { derives = [ PartialEq, Eq, Copy ]}, + BootSettings = { derives = [ Default ] }, + CpuidEntry = { derives = [ PartialEq, Eq, Copy ] }, InstanceMetadata = { derives = [ PartialEq ] }, SpecKey = { derives = [ PartialEq, Eq, Ord, PartialOrd, Hash ] }, }