diff --git a/Cargo.lock b/Cargo.lock index 44ef4eccc5..5bf0b2023d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1411,6 +1411,7 @@ dependencies = [ "camino-tempfile", "chrono", "derive_more", + "diffus", "expectorate", "itertools 0.13.0", "omicron-common", @@ -2366,6 +2367,28 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" +[[package]] +name = "diffus" +version = "0.10.0" +source = "git+https://github.com/oxidecomputer/diffus?branch=oxide/main#f6abe39bffd875b5fb1ebabf8144da15e3effe16" +dependencies = [ + "diffus-derive", + "itertools 0.10.5", + "newtype-uuid", + "oxnet", + "uuid", +] + +[[package]] +name = "diffus-derive" +version = "0.10.0" +source = "git+https://github.com/oxidecomputer/diffus?branch=oxide/main#f6abe39bffd875b5fb1ebabf8144da15e3effe16" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.10.7" @@ -6065,6 +6088,7 @@ dependencies = [ "chrono", "clickhouse-admin-types", "debug-ignore", + "diffus", "expectorate", "gateway-client", "illumos-utils", @@ -6166,6 +6190,7 @@ dependencies = [ name = "nexus-sled-agent-shared" version = "0.1.0" dependencies = [ + "diffus", "illumos-utils", "omicron-common", "omicron-passwords", @@ -6268,6 +6293,7 @@ dependencies = [ "cookie", "derive-where", "derive_more", + "diffus", "dropshot 0.13.0", "futures", "gateway-client", @@ -6692,6 +6718,7 @@ dependencies = [ "camino", "camino-tempfile", "chrono", + "diffus", "dropshot 0.13.0", "expectorate", "futures", @@ -7342,6 +7369,7 @@ dependencies = [ name = "omicron-uuid-kinds" version = "0.1.0" dependencies = [ + "diffus", "newtype-uuid", "paste", "schemars", @@ -10379,9 +10407,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", "memchr", @@ -13235,7 +13263,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.48.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index bb9ff0e80f..b831bc489b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -364,6 +364,8 @@ derive-where = "1.2.7" # Having the i-implement-... feature here makes diesel go away from the workspace-hack diesel = { version = "2.2.4", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "r2d2", "chrono", "serde_json", "network-address", "uuid"] } diesel-dtrace = "0.4.2" +#diffus = { version = "0.10.0", features = ["uuid-impl", "derive"] } +diffus = { git = "https://github.com/oxidecomputer/diffus", branch = "oxide/main", features = ["uuid-impl", "derive", "newtype-uuid-impl", "oxnet-impl"] } dns-server = { path = "dns-server" } dns-server-api = { path = "dns-server-api" } dns-service-client = { path = "clients/dns-service-client" } @@ -576,7 +578,7 @@ secrecy = "0.8.0" semver = { version = "1.0.23", features = ["std", "serde"] } serde = { version = "1.0", default-features = false, features = [ "derive", "rc" ] } serde_human_bytes = { git = "https://github.com/oxidecomputer/serde_human_bytes", branch = "main" } -serde_json = "1.0.132" +serde_json = "1.0.133" serde_path_to_error = "0.1.16" serde_tokenstream = "0.2" serde_urlencoded = "0.7.1" diff --git a/clickhouse-admin/types/Cargo.toml b/clickhouse-admin/types/Cargo.toml index f57b1c5052..c8ee984abe 100644 --- a/clickhouse-admin/types/Cargo.toml +++ b/clickhouse-admin/types/Cargo.toml @@ -14,6 +14,7 @@ camino.workspace = true camino-tempfile.workspace = true chrono.workspace = true derive_more.workspace = true +diffus.workspace = true itertools.workspace = true omicron-common.workspace = true omicron-workspace-hack.workspace = true @@ -25,4 +26,4 @@ expectorate.workspace = true [dev-dependencies] slog-async.workspace = true -slog-term.workspace = true \ No newline at end of file +slog-term.workspace = true diff --git a/clickhouse-admin/types/src/lib.rs b/clickhouse-admin/types/src/lib.rs index 3b8696438c..726f4ad6e4 100644 --- a/clickhouse-admin/types/src/lib.rs +++ b/clickhouse-admin/types/src/lib.rs @@ -7,6 +7,7 @@ use atomicwrites::AtomicFile; use camino::Utf8PathBuf; use chrono::{DateTime, Utc}; use derive_more::{Add, AddAssign, Display, From}; +use diffus::Diffus; use itertools::Itertools; use omicron_common::api::external::Generation; use schemars::{ @@ -56,6 +57,7 @@ pub const OXIMETER_CLUSTER: &str = "oximeter_cluster"; JsonSchema, Serialize, Deserialize, + Diffus, )] pub struct KeeperId(pub u64); @@ -75,6 +77,7 @@ pub struct KeeperId(pub u64); JsonSchema, Serialize, Deserialize, + Diffus, )] pub struct ServerId(pub u64); diff --git a/common/Cargo.toml b/common/Cargo.toml index 0d122e602b..f2797ed2b4 100644 --- a/common/Cargo.toml +++ b/common/Cargo.toml @@ -20,6 +20,7 @@ async-trait.workspace = true backoff.workspace = true camino.workspace = true chrono.workspace = true +diffus.workspace = true dropshot.workspace = true futures.workspace = true hex.workspace = true diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 38a9de0564..d8022f51c0 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -18,6 +18,7 @@ use anyhow::Context; use api_identity::ObjectIdentity; use chrono::DateTime; use chrono::Utc; +use diffus::{edit, Diffable, Diffus}; use dropshot::HttpError; pub use dropshot::PaginationOrder; pub use error::*; @@ -211,6 +212,7 @@ impl<'a> TryFrom<&DataPageParams<'a, NameOrId>> for DataPageParams<'a, Uuid> { )] #[display("{0}")] #[serde(try_from = "String")] +#[derive(Diffus)] pub struct Name(String); /// `Name::try_from(String)` is the primary method for constructing an Name @@ -614,6 +616,7 @@ impl JsonSchema for RoleName { Eq, PartialOrd, Ord, + Diffus, )] pub struct ByteCount(u64); @@ -748,6 +751,7 @@ impl From for i64 { PartialEq, PartialOrd, Serialize, + Diffus, )] pub struct Generation(u64); @@ -1935,6 +1939,17 @@ impl JsonSchema for L4PortRange { )] pub struct MacAddr(pub macaddr::MacAddr6); +impl<'a> Diffable<'a> for MacAddr { + type Diff = (&'a Self, &'a Self); + fn diff(&'a self, other: &'a Self) -> edit::Edit<'a, Self> { + if self == other { + edit::Edit::Copy(self) + } else { + edit::Edit::Change((self, other)) + } + } +} + impl MacAddr { // Guest MAC addresses begin with the Oxide OUI A8:40:25. Further, guest // address are constrained to be in the virtual address range @@ -2098,6 +2113,7 @@ impl JsonSchema for MacAddr { Deserialize, Serialize, JsonSchema, + Diffus, )] pub struct Vni(u32); diff --git a/common/src/api/internal/shared.rs b/common/src/api/internal/shared.rs index 94440df2d5..ff14e899fb 100644 --- a/common/src/api/internal/shared.rs +++ b/common/src/api/internal/shared.rs @@ -8,6 +8,7 @@ use crate::{ address::NUM_SOURCE_NAT_PORTS, api::external::{self, BfdMode, ImportExportPolicy, Name, Vni}, }; +use diffus::Diffus; use oxnet::{IpNet, Ipv4Net, Ipv6Net}; use schemars::JsonSchema; use serde::{de, Deserialize, Deserializer, Serialize, Serializer}; @@ -35,6 +36,7 @@ use super::nexus::HostIdentifier; Serialize, JsonSchema, Hash, + Diffus, )] #[serde(tag = "type", rename_all = "snake_case")] pub enum NetworkInterfaceKind { @@ -48,7 +50,15 @@ pub enum NetworkInterfaceKind { /// Information required to construct a virtual network interface #[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, + Clone, + Debug, + Deserialize, + Serialize, + JsonSchema, + PartialEq, + Eq, + Hash, + Diffus, )] pub struct NetworkInterface { pub id: Uuid, @@ -68,7 +78,9 @@ pub struct NetworkInterface { /// outbound network connections from guests or services. // Note that `Deserialize` is manually implemented; if you make any changes to // the fields of this structure, you must make them to that implementation too. -#[derive(Debug, Clone, Copy, Serialize, JsonSchema, PartialEq, Eq, Hash)] +#[derive( + Debug, Clone, Copy, Serialize, JsonSchema, PartialEq, Eq, Hash, Diffus, +)] pub struct SourceNatConfig { /// The external address provided to the instance or service. pub ip: IpAddr, @@ -871,7 +883,9 @@ pub struct ExternalIpGatewayMap { } /// Describes the purpose of the dataset. -#[derive(Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, EnumCount)] +#[derive( + Debug, Clone, PartialEq, Eq, Ord, PartialOrd, Hash, EnumCount, Diffus, +)] #[cfg_attr(feature = "testing", derive(test_strategy::Arbitrary))] pub enum DatasetKind { // Durable datasets for zones diff --git a/common/src/disk.rs b/common/src/disk.rs index 99c2b2db7b..df6efe3196 100644 --- a/common/src/disk.rs +++ b/common/src/disk.rs @@ -6,6 +6,7 @@ use anyhow::bail; use camino::{Utf8Path, Utf8PathBuf}; +use diffus::Diffus; use omicron_uuid_kinds::DatasetUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::ZpoolUuid; @@ -176,6 +177,7 @@ impl DatasetName { Hash, PartialOrd, Ord, + Diffus, )] pub struct GzipLevel(u8); @@ -218,6 +220,7 @@ impl FromStr for GzipLevel { Hash, PartialOrd, Ord, + Diffus, )] #[serde(tag = "type", rename_all = "snake_case")] pub enum CompressionAlgorithm { @@ -412,6 +415,7 @@ impl DatasetsManagementResult { Serialize, Deserialize, JsonSchema, + Diffus, )] pub struct DiskIdentity { pub vendor: String, diff --git a/common/src/zpool_name.rs b/common/src/zpool_name.rs index df5ca8ea31..9852b46120 100644 --- a/common/src/zpool_name.rs +++ b/common/src/zpool_name.rs @@ -5,6 +5,7 @@ //! Zpool labels and kinds shared between Nexus and Sled Agents use camino::{Utf8Path, Utf8PathBuf}; +use diffus::Diffus; use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -15,7 +16,7 @@ pub const ZPOOL_INTERNAL_PREFIX: &str = "oxi_"; /// Describes the different classes of Zpools. #[derive( - Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema, + Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, JsonSchema, Diffus, )] #[serde(rename_all = "snake_case")] pub enum ZpoolKind { @@ -29,7 +30,7 @@ pub enum ZpoolKind { /// /// This expects that the format will be: `ox{i,p}_` - we parse the prefix /// when reading the structure, and validate that the UUID can be utilized. -#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Diffus)] pub struct ZpoolName { id: ZpoolUuid, kind: ZpoolKind, diff --git a/nexus-sled-agent-shared/Cargo.toml b/nexus-sled-agent-shared/Cargo.toml index 504cd92c37..ea83cb67ae 100644 --- a/nexus-sled-agent-shared/Cargo.toml +++ b/nexus-sled-agent-shared/Cargo.toml @@ -7,6 +7,7 @@ edition = "2021" workspace = true [dependencies] +diffus.workspace = true illumos-utils.workspace = true omicron-common.workspace = true omicron-passwords.workspace = true diff --git a/nexus-sled-agent-shared/src/inventory.rs b/nexus-sled-agent-shared/src/inventory.rs index 5fb2d55203..88fd3a0978 100644 --- a/nexus-sled-agent-shared/src/inventory.rs +++ b/nexus-sled-agent-shared/src/inventory.rs @@ -6,6 +6,7 @@ use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV6}; +use diffus::Diffus; use omicron_common::{ api::{ external::{ByteCount, Generation}, @@ -173,7 +174,15 @@ impl OmicronZoneConfig { /// Describes a persistent ZFS dataset associated with an Omicron zone #[derive( - Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, + Clone, + Debug, + Deserialize, + Serialize, + JsonSchema, + PartialEq, + Eq, + Hash, + Diffus, )] pub struct OmicronZoneDataset { pub pool_name: ZpoolName, diff --git a/nexus/reconfigurator/planning/Cargo.toml b/nexus/reconfigurator/planning/Cargo.toml index efed173a71..63c5e3e44f 100644 --- a/nexus/reconfigurator/planning/Cargo.toml +++ b/nexus/reconfigurator/planning/Cargo.toml @@ -11,6 +11,7 @@ anyhow.workspace = true clickhouse-admin-types.workspace = true chrono.workspace = true debug-ignore.workspace = true +diffus.workspace = true gateway-client.workspace = true illumos-utils.workspace = true indexmap.workspace = true diff --git a/nexus/reconfigurator/planning/src/planner.rs b/nexus/reconfigurator/planning/src/planner.rs index a18bb6e3d3..47ccc6f74c 100644 --- a/nexus/reconfigurator/planning/src/planner.rs +++ b/nexus/reconfigurator/planning/src/planner.rs @@ -797,6 +797,7 @@ mod test { use chrono::Utc; use clickhouse_admin_types::ClickhouseKeeperClusterMembership; use clickhouse_admin_types::KeeperId; + use diffus::Diffable; use expectorate::assert_contents; use nexus_sled_agent_shared::inventory::ZoneKind; use nexus_types::deployment::blueprint_zone_type; @@ -909,6 +910,12 @@ mod test { "2 -> 3 (expect new NTP zone on new sled):\n{}", diff.display() ); + let diffus_diff = blueprint3.diff(&blueprint2); + println!("_______DIFFUS __________\n"); + let change = diffus_diff.change(); + println!("{:#?}", diffus_diff); + println!("{:#?}", change); + println!("________DIFFUS __________\n"); assert_contents( "tests/output/planner_basic_add_sled_2_3.txt", &diff.display().to_string(), diff --git a/nexus/types/Cargo.toml b/nexus/types/Cargo.toml index 8990b0b83b..edf22679ef 100644 --- a/nexus/types/Cargo.toml +++ b/nexus/types/Cargo.toml @@ -17,6 +17,7 @@ clickhouse-admin-types.workspace = true cookie.workspace = true derive-where.workspace = true derive_more.workspace = true +diffus.workspace = true dropshot.workspace = true futures.workspace = true http.workspace = true diff --git a/nexus/types/src/deployment.rs b/nexus/types/src/deployment.rs index 806df52711..ea41375d78 100644 --- a/nexus/types/src/deployment.rs +++ b/nexus/types/src/deployment.rs @@ -18,6 +18,7 @@ use crate::inventory::Collection; pub use crate::inventory::SourceNatConfig; pub use crate::inventory::ZpoolName; use blueprint_diff::ClickhouseClusterConfigDiffTablesForSingleBlueprint; +use diffus::Diffus; use nexus_sled_agent_shared::inventory::OmicronZoneConfig; use nexus_sled_agent_shared::inventory::OmicronZonesConfig; use nexus_sled_agent_shared::inventory::ZoneKind; @@ -137,7 +138,9 @@ pub use blueprint_diff::BlueprintDiff; // zones deployed on each host and some supporting configuration (e.g., DNS). // This is aimed at supporting add/remove sleds. The plan is to grow this to // include more of the system as we support more use cases. -#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)] +#[derive( + Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, +)] pub struct Blueprint { /// unique identifier for this blueprint pub id: Uuid, @@ -187,6 +190,7 @@ pub struct Blueprint { pub clickhouse_cluster_config: Option, /// when this blueprint was generated (for debugging) + #[diffus(ignore)] pub time_created: chrono::DateTime, /// identity of the component that generated the blueprint (for debugging) /// This would generally be the Uuid of a Nexus instance. @@ -536,7 +540,9 @@ impl<'a> fmt::Display for BlueprintDisplay<'a> { /// per-zone [`BlueprintZoneDisposition`]. /// /// Part of [`Blueprint`]. -#[derive(Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize)] +#[derive( + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, +)] pub struct BlueprintZonesConfig { /// Generation number of this configuration. /// @@ -630,7 +636,9 @@ fn zone_sort_key(z: &T) -> impl Ord { /// Describes one Omicron-managed zone in a blueprint. /// /// Part of [`BlueprintZonesConfig`]. -#[derive(Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize)] +#[derive( + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, +)] pub struct BlueprintZoneConfig { /// The disposition (desired state) of this zone recorded in the blueprint. pub disposition: BlueprintZoneDisposition, @@ -641,6 +649,12 @@ pub struct BlueprintZoneConfig { pub zone_type: BlueprintZoneType, } +impl diffus::Same for BlueprintZoneConfig { + fn same(&self, other: &Self) -> bool { + self == other + } +} + impl BlueprintZoneConfig { /// Returns the underlay IP address associated with this zone. /// @@ -692,6 +706,7 @@ impl From for OmicronZoneConfig { Deserialize, Serialize, EnumIter, + Diffus, )] #[serde(rename_all = "snake_case")] pub enum BlueprintZoneDisposition { @@ -835,6 +850,7 @@ pub enum BlueprintDatasetFilter { Deserialize, Serialize, EnumIter, + Diffus, )] #[serde(rename_all = "snake_case")] pub enum BlueprintPhysicalDiskDisposition { @@ -866,7 +882,9 @@ impl BlueprintPhysicalDiskDisposition { } /// Information about an Omicron physical disk as recorded in a bluerprint. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Diffus, +)] pub struct BlueprintPhysicalDiskConfig { pub disposition: BlueprintPhysicalDiskDisposition, pub identity: DiskIdentity, @@ -877,12 +895,20 @@ pub struct BlueprintPhysicalDiskConfig { /// Information about Omicron physical disks as recorded in a blueprint. /// /// Part of [`Blueprint`]. -#[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] +#[derive( + Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Diffus, +)] pub struct BlueprintPhysicalDisksConfig { pub generation: Generation, pub disks: Vec, } +impl diffus::Same for BlueprintPhysicalDiskConfig { + fn same(&self, other: &Self) -> bool { + self == other + } +} + // Required by RSS impl Default for BlueprintPhysicalDisksConfig { fn default() -> Self { @@ -917,7 +943,9 @@ impl From for OmicronPhysicalDisksConfig { } /// Information about Omicron datasets as recorded in a blueprint. -#[derive(Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize)] +#[derive( + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, +)] pub struct BlueprintDatasetsConfig { pub generation: Generation, pub datasets: BTreeMap, @@ -952,6 +980,7 @@ impl From for DatasetsConfig { Deserialize, Serialize, EnumIter, + Diffus, )] #[serde(rename_all = "snake_case")] pub enum BlueprintDatasetDisposition { @@ -980,7 +1009,9 @@ impl BlueprintDatasetDisposition { } /// Information about a dataset as recorded in a blueprint -#[derive(Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize)] +#[derive( + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, +)] pub struct BlueprintDatasetConfig { // TODO: Display this in diffs - leave for now, for backwards compat pub disposition: BlueprintDatasetDisposition, diff --git a/nexus/types/src/deployment/clickhouse.rs b/nexus/types/src/deployment/clickhouse.rs index d0612e2ddf..f8443c6afe 100644 --- a/nexus/types/src/deployment/clickhouse.rs +++ b/nexus/types/src/deployment/clickhouse.rs @@ -5,6 +5,7 @@ //! Types used in blueprints related to clickhouse configuration use clickhouse_admin_types::{KeeperId, ServerId}; +use diffus::Diffus; use omicron_common::api::external::Generation; use omicron_uuid_kinds::OmicronZoneUuid; use schemars::JsonSchema; @@ -12,7 +13,9 @@ use serde::{Deserialize, Serialize}; use std::collections::BTreeMap; /// Global configuration for all clickhouse servers (replicas) and keepers -#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)] +#[derive( + Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, +)] pub struct ClickhouseClusterConfig { /// The last update to the clickhouse cluster configuration /// diff --git a/nexus/types/src/deployment/network_resources.rs b/nexus/types/src/deployment/network_resources.rs index cdabbc7fdc..358e7c229d 100644 --- a/nexus/types/src/deployment/network_resources.rs +++ b/nexus/types/src/deployment/network_resources.rs @@ -5,6 +5,7 @@ use super::tri_map::TriMap; use super::tri_map::TriMapEntry; use anyhow::anyhow; +use diffus::Diffus; use omicron_common::api::external::MacAddr; use omicron_common::api::internal::shared::SourceNatConfig; use omicron_uuid_kinds::ExternalIpUuid; @@ -199,7 +200,16 @@ pub enum OmicronZoneExternalIpKey { /// necessary for blueprint planning, and requires that the zone have a single /// IP. #[derive( - Debug, Clone, Copy, Hash, PartialEq, Eq, JsonSchema, Serialize, Deserialize, + Debug, + Clone, + Copy, + Hash, + PartialEq, + Eq, + JsonSchema, + Serialize, + Deserialize, + Diffus, )] pub struct OmicronZoneExternalFloatingIp { pub id: ExternalIpUuid, @@ -208,7 +218,15 @@ pub struct OmicronZoneExternalFloatingIp { /// Floating external address with port allocated to an Omicron-managed zone. #[derive( - Debug, Clone, Copy, PartialEq, Eq, JsonSchema, Serialize, Deserialize, + Debug, + Clone, + Copy, + PartialEq, + Eq, + JsonSchema, + Serialize, + Deserialize, + Diffus, )] pub struct OmicronZoneExternalFloatingAddr { pub id: ExternalIpUuid, @@ -227,7 +245,16 @@ impl OmicronZoneExternalFloatingAddr { /// necessary for blueprint planning, and requires that the zone have a single /// IP. #[derive( - Debug, Clone, Copy, Hash, PartialEq, Eq, JsonSchema, Serialize, Deserialize, + Debug, + Clone, + Copy, + Hash, + PartialEq, + Eq, + JsonSchema, + Serialize, + Deserialize, + Diffus, )] pub struct OmicronZoneExternalSnatIp { pub id: ExternalIpUuid, diff --git a/nexus/types/src/deployment/planning_input.rs b/nexus/types/src/deployment/planning_input.rs index 0dda916509..1876440d47 100644 --- a/nexus/types/src/deployment/planning_input.rs +++ b/nexus/types/src/deployment/planning_input.rs @@ -17,6 +17,7 @@ use crate::external_api::views::SledState; use chrono::DateTime; use chrono::Utc; use clap::ValueEnum; +use diffus::Diffus; use ipnetwork::IpNetwork; use omicron_common::address::IpRange; use omicron_common::address::Ipv6Subnet; @@ -376,6 +377,7 @@ impl CockroachDbSettings { Deserialize, Serialize, JsonSchema, + Diffus, )] pub enum CockroachDbClusterVersion { #[display("22.1")] @@ -408,7 +410,15 @@ impl CockroachDbClusterVersion { /// Whether to set `cluster.preserve_downgrade_option` and what to set it to. #[derive( - Clone, Copy, Debug, Eq, PartialEq, Deserialize, Serialize, JsonSchema, + Clone, + Copy, + Debug, + Eq, + PartialEq, + Deserialize, + Serialize, + JsonSchema, + Diffus, )] #[serde(tag = "action", content = "data", rename_all = "snake_case")] pub enum CockroachDbPreserveDowngrade { diff --git a/nexus/types/src/deployment/zone_type.rs b/nexus/types/src/deployment/zone_type.rs index 86310cfc8f..bb5225986c 100644 --- a/nexus/types/src/deployment/zone_type.rs +++ b/nexus/types/src/deployment/zone_type.rs @@ -9,6 +9,7 @@ //! that is not needed by sled-agent. use super::OmicronZoneExternalIp; +use diffus::Diffus; use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use nexus_sled_agent_shared::inventory::OmicronZoneType; use nexus_sled_agent_shared::inventory::ZoneKind; @@ -21,7 +22,9 @@ use serde::Serialize; use std::net::Ipv6Addr; use std::net::SocketAddrV6; -#[derive(Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize)] +#[derive( + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, +)] #[serde(tag = "type", rename_all = "snake_case")] pub enum BlueprintZoneType { BoundaryNtp(blueprint_zone_type::BoundaryNtp), @@ -325,6 +328,7 @@ pub mod blueprint_zone_type { use crate::deployment::OmicronZoneExternalFloatingAddr; use crate::deployment::OmicronZoneExternalFloatingIp; use crate::deployment::OmicronZoneExternalSnatIp; + use diffus::Diffus; use nexus_sled_agent_shared::inventory::OmicronZoneDataset; use omicron_common::api::internal::shared::NetworkInterface; use schemars::JsonSchema; @@ -335,7 +339,7 @@ pub mod blueprint_zone_type { use std::net::SocketAddrV6; #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct BoundaryNtp { pub address: SocketAddrV6, @@ -349,7 +353,7 @@ pub mod blueprint_zone_type { /// Used in single-node clickhouse setups #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct Clickhouse { pub address: SocketAddrV6, @@ -357,7 +361,7 @@ pub mod blueprint_zone_type { } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct ClickhouseKeeper { pub address: SocketAddrV6, @@ -366,7 +370,7 @@ pub mod blueprint_zone_type { /// Used in replicated clickhouse setups #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct ClickhouseServer { pub address: SocketAddrV6, @@ -374,7 +378,7 @@ pub mod blueprint_zone_type { } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct CockroachDb { pub address: SocketAddrV6, @@ -382,7 +386,7 @@ pub mod blueprint_zone_type { } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct Crucible { pub address: SocketAddrV6, @@ -390,14 +394,14 @@ pub mod blueprint_zone_type { } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct CruciblePantry { pub address: SocketAddrV6, } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct ExternalDns { pub dataset: OmicronZoneDataset, @@ -410,7 +414,7 @@ pub mod blueprint_zone_type { } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct InternalDns { pub dataset: OmicronZoneDataset, @@ -430,14 +434,14 @@ pub mod blueprint_zone_type { } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct InternalNtp { pub address: SocketAddrV6, } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct Nexus { /// The address at which the internal nexus server is reachable. @@ -453,7 +457,7 @@ pub mod blueprint_zone_type { } #[derive( - Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, + Debug, Clone, Eq, PartialEq, JsonSchema, Deserialize, Serialize, Diffus, )] pub struct Oximeter { pub address: SocketAddrV6, diff --git a/nexus/types/src/external_api/views.rs b/nexus/types/src/external_api/views.rs index 0fd45c0666..94b2279906 100644 --- a/nexus/types/src/external_api/views.rs +++ b/nexus/types/src/external_api/views.rs @@ -11,6 +11,7 @@ use crate::identity::AssetIdentityMetadata; use api_identity::ObjectIdentity; use chrono::DateTime; use chrono::Utc; +use diffus::Diffus; use omicron_common::api::external::{ AllowedSourceIps as ExternalAllowedSourceIps, ByteCount, Digest, Error, IdentityMetadata, InstanceState, Name, ObjectIdentity, RoleName, @@ -704,6 +705,7 @@ impl fmt::Display for SledPolicy { PartialEq, Eq, EnumIter, + Diffus, )] #[serde(rename_all = "snake_case")] pub enum SledState { diff --git a/uuid-kinds/Cargo.toml b/uuid-kinds/Cargo.toml index 9ea2f8223c..0a80fab9c9 100644 --- a/uuid-kinds/Cargo.toml +++ b/uuid-kinds/Cargo.toml @@ -12,6 +12,7 @@ workspace = true # within omicron. [dependencies] +diffus.workspace = true newtype-uuid.workspace = true schemars = { workspace = true, optional = true } paste.workspace = true diff --git a/uuid-kinds/src/lib.rs b/uuid-kinds/src/lib.rs index 42c50379ce..e4f65d7039 100644 --- a/uuid-kinds/src/lib.rs +++ b/uuid-kinds/src/lib.rs @@ -14,6 +14,7 @@ pub use newtype_uuid::{ GenericUuid, ParseError, TagError, TypedUuid, TypedUuidKind, TypedUuidTag, }; +use diffus::Diffus; #[cfg(feature = "schemars08")] use schemars::JsonSchema; @@ -22,6 +23,7 @@ macro_rules! impl_typed_uuid_kind { $( paste::paste! { #[cfg_attr(feature = "schemars08", derive(JsonSchema))] + #[derive(Diffus)] pub enum [< $kind Kind>] {} impl TypedUuidKind for [< $kind Kind >] {