From 5c7a302f41c63f4266b054fd5c04551fe4064786 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 11 Feb 2025 06:33:04 +0000 Subject: [PATCH] [spr] initial version Created using spr 1.3.6-beta.1 --- Cargo.lock | 43 ++-- Cargo.toml | 16 +- common/src/api/external/mod.rs | 10 +- common/src/zpool_name.rs | 7 +- nexus/reconfigurator/planning/src/planner.rs | 27 +-- nexus/types/src/deployment/blueprint_diff.rs | 203 ++++++++++--------- 6 files changed, 160 insertions(+), 146 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3434e15dce8..54c38cc2ce3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2070,8 +2070,9 @@ dependencies = [ [[package]] name = "daft" -version = "0.1.0" -source = "git+https://github.com/oxidecomputer/daft?branch=main#9e7b55349f61bded974cba9c1727a70a62586a37" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a75caf1eeef382d47bf5d3012b5ec521311cd876a1304ac8807ec86d4df42a7" dependencies = [ "daft-derive", "newtype-uuid", @@ -2082,8 +2083,9 @@ dependencies = [ [[package]] name = "daft-derive" -version = "0.1.0" -source = "git+https://github.com/oxidecomputer/daft?branch=main#9e7b55349f61bded974cba9c1727a70a62586a37" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a851e4efac7afda4a5e1a11fea1d65ef528dbdcff08177d7087e4bb6225e60a9" dependencies = [ "proc-macro2", "quote", @@ -2183,7 +2185,7 @@ dependencies = [ [[package]] name = "ddm-admin-client" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/maghemite?rev=93cd0d642cf1b58f9f4528275e2a2aa758e9feb3#93cd0d642cf1b58f9f4528275e2a2aa758e9feb3" +source = "git+https://github.com/oxidecomputer/maghemite?rev=e8ef9ce16c08413cc544ac63fd8d991ecb99cd2b#e8ef9ce16c08413cc544ac63fd8d991ecb99cd2b" dependencies = [ "oxnet", "percent-encoding", @@ -2383,9 +2385,9 @@ dependencies = [ [[package]] name = "diesel" -version = "2.2.6" +version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccf1bedf64cdb9643204a36dd15b19a6ce8e7aa7f7b105868e9f1fad5ffa7d12" +checksum = "04001f23ba8843dc315804fa324000376084dfb1c30794ff68dd279e6e5696d5" dependencies = [ "bitflags 2.6.0", "byteorder", @@ -4492,7 +4494,7 @@ dependencies = [ [[package]] name = "illumos-sys-hdrs" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=b56afeeb14e0042cbd7bda85b166ed86ee17820e#b56afeeb14e0042cbd7bda85b166ed86ee17820e" +source = "git+https://github.com/oxidecomputer/opte?rev=46539d5b15aa93cb938f22966838360e87568b56#46539d5b15aa93cb938f22966838360e87568b56" [[package]] name = "illumos-utils" @@ -4871,9 +4873,9 @@ checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "ipnetwork" -version = "0.20.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +checksum = "cf370abdafd54d13e54a620e8c3e1145f28e46cc9d704bc6d94414559df41763" dependencies = [ "schemars", "serde", @@ -4989,7 +4991,7 @@ dependencies = [ [[package]] name = "kstat-macro" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=b56afeeb14e0042cbd7bda85b166ed86ee17820e#b56afeeb14e0042cbd7bda85b166ed86ee17820e" +source = "git+https://github.com/oxidecomputer/opte?rev=46539d5b15aa93cb938f22966838360e87568b56#46539d5b15aa93cb938f22966838360e87568b56" dependencies = [ "quote", "syn 2.0.96", @@ -5088,7 +5090,7 @@ checksum = "b024e211b1b371da58cd69e4fb8fa4ed16915edcc0e2e1fb04ac4bad61959f25" [[package]] name = "libfalcon" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/falcon?branch=main#651fb5889d66be90ac1afa4a730c573b643aef1e" +source = "git+https://github.com/oxidecomputer/falcon?branch=main#f3fe0542198c08bbb82d16f168e6482db9bec5b9" dependencies = [ "anstyle", "anyhow", @@ -5162,7 +5164,7 @@ checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" [[package]] name = "libnet" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/netadm-sys?branch=main#e07ad76458eb50601e0da4f9da16dbc942bfc2ba" +source = "git+https://github.com/oxidecomputer/netadm-sys?branch=main#f4eae3d8070760922da93b9edd56ca4103b4c390" dependencies = [ "anyhow", "cfg-if", @@ -5184,7 +5186,7 @@ dependencies = [ [[package]] name = "libnet" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/netadm-sys#e07ad76458eb50601e0da4f9da16dbc942bfc2ba" +source = "git+https://github.com/oxidecomputer/netadm-sys#f4eae3d8070760922da93b9edd56ca4103b4c390" dependencies = [ "anyhow", "cfg-if", @@ -5518,7 +5520,7 @@ dependencies = [ [[package]] name = "mg-admin-client" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/maghemite?rev=93cd0d642cf1b58f9f4528275e2a2aa758e9feb3#93cd0d642cf1b58f9f4528275e2a2aa758e9feb3" +source = "git+https://github.com/oxidecomputer/maghemite?rev=e8ef9ce16c08413cc544ac63fd8d991ecb99cd2b#e8ef9ce16c08413cc544ac63fd8d991ecb99cd2b" dependencies = [ "anyhow", "chrono", @@ -7794,7 +7796,7 @@ dependencies = [ [[package]] name = "opte" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=b56afeeb14e0042cbd7bda85b166ed86ee17820e#b56afeeb14e0042cbd7bda85b166ed86ee17820e" +source = "git+https://github.com/oxidecomputer/opte?rev=46539d5b15aa93cb938f22966838360e87568b56#46539d5b15aa93cb938f22966838360e87568b56" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -7813,7 +7815,7 @@ dependencies = [ [[package]] name = "opte-api" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=b56afeeb14e0042cbd7bda85b166ed86ee17820e#b56afeeb14e0042cbd7bda85b166ed86ee17820e" +source = "git+https://github.com/oxidecomputer/opte?rev=46539d5b15aa93cb938f22966838360e87568b56#46539d5b15aa93cb938f22966838360e87568b56" dependencies = [ "illumos-sys-hdrs", "ingot", @@ -7826,7 +7828,7 @@ dependencies = [ [[package]] name = "opte-ioctl" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=b56afeeb14e0042cbd7bda85b166ed86ee17820e#b56afeeb14e0042cbd7bda85b166ed86ee17820e" +source = "git+https://github.com/oxidecomputer/opte?rev=46539d5b15aa93cb938f22966838360e87568b56#46539d5b15aa93cb938f22966838360e87568b56" dependencies = [ "libc", "libnet 0.1.0 (git+https://github.com/oxidecomputer/netadm-sys)", @@ -7895,7 +7897,7 @@ dependencies = [ [[package]] name = "oxide-vpc" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/opte?rev=b56afeeb14e0042cbd7bda85b166ed86ee17820e#b56afeeb14e0042cbd7bda85b166ed86ee17820e" +source = "git+https://github.com/oxidecomputer/opte?rev=46539d5b15aa93cb938f22966838360e87568b56#46539d5b15aa93cb938f22966838360e87568b56" dependencies = [ "cfg-if", "illumos-sys-hdrs", @@ -8217,7 +8219,8 @@ dependencies = [ [[package]] name = "oxnet" version = "0.1.0" -source = "git+https://github.com/oxidecomputer/oxnet#49ee85dcd294901031c3395ee773363db1cdc289" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7aba867c36df803039621068faf1630d3039eb999c2f6c3950d1064d4fbbdf" dependencies = [ "ipnetwork", "schemars", diff --git a/Cargo.toml b/Cargo.toml index 462e87b3bc8..fcd757a1cfb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -369,7 +369,7 @@ crucible-common = { git = "https://github.com/oxidecomputer/crucible", rev = "03 # NOTE: See above! csv = "1.3.1" curve25519-dalek = "4" -daft = { git = "https://github.com/oxidecomputer/daft", branch = "main", features = ["newtype-uuid1", "oxnet01", "uuid1"] } +daft = { version = "0.1.1", features = ["derive", "newtype-uuid1", "oxnet01", "uuid1"] } datatest-stable = "0.2.9" display-error-chain = "0.2.2" omicron-ddm-admin-client = { path = "clients/ddm-admin-client" } @@ -378,7 +378,7 @@ debug-ignore = "1.0.5" derive_more = "0.99.18" derive-where = "1.2.7" # Having the i-implement-... feature here makes diesel go away from the workspace-hack -diesel = { version = "2.2.6", features = ["i-implement-a-third-party-backend-and-opt-into-breaking-changes", "postgres", "r2d2", "chrono", "serde_json", "network-address", "uuid"] } +diesel = { version = "2.2.7", 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" dns-server = { path = "dns-server" } dns-server-api = { path = "dns-server-api" } @@ -451,7 +451,7 @@ ipcc = { path = "ipcc" } ipnet = "2.9" itertools = "0.13.0" internet-checksum = "0.2" -ipnetwork = { version = "0.20", features = ["schemars"] } +ipnetwork = { version = "0.21", features = ["schemars", "serde"] } ispf = { git = "https://github.com/oxidecomputer/ispf" } key-manager = { path = "key-manager" } kstat-rs = "0.2.4" @@ -466,8 +466,8 @@ macaddr = { version = "1.0.1", features = ["serde_std"] } maplit = "1.0.2" mockall = "0.13" newtype_derive = "0.1.6" -mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "93cd0d642cf1b58f9f4528275e2a2aa758e9feb3" } -ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "93cd0d642cf1b58f9f4528275e2a2aa758e9feb3" } +mg-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "e8ef9ce16c08413cc544ac63fd8d991ecb99cd2b" } +ddm-admin-client = { git = "https://github.com/oxidecomputer/maghemite", rev = "e8ef9ce16c08413cc544ac63fd8d991ecb99cd2b" } multimap = "0.10.0" nexus-auth = { path = "nexus/auth" } nexus-client = { path = "clients/nexus-client" } @@ -515,9 +515,9 @@ omicron-test-utils = { path = "test-utils" } omicron-workspace-hack = "0.1.0" omicron-zone-package = "0.12.0" oxide-client = { path = "clients/oxide-client" } -oxide-vpc = { git = "https://github.com/oxidecomputer/opte", rev = "b56afeeb14e0042cbd7bda85b166ed86ee17820e", features = [ "api", "std" ] } +oxide-vpc = { git = "https://github.com/oxidecomputer/opte", rev = "46539d5b15aa93cb938f22966838360e87568b56", features = [ "api", "std" ] } oxlog = { path = "dev-tools/oxlog" } -oxnet = { git = "https://github.com/oxidecomputer/oxnet" } +oxnet = "0.1.0" once_cell = "1.20.2" openapi-lint = { git = "https://github.com/oxidecomputer/openapi-lint", branch = "main" } openapi-manager-types = { path = "dev-tools/openapi-manager/types" } @@ -525,7 +525,7 @@ openapiv3 = "2.0.0" # must match samael's crate! openssl = "0.10" openssl-sys = "0.9" -opte-ioctl = { git = "https://github.com/oxidecomputer/opte", rev = "b56afeeb14e0042cbd7bda85b166ed86ee17820e" } +opte-ioctl = { git = "https://github.com/oxidecomputer/opte", rev = "46539d5b15aa93cb938f22966838360e87568b56" } oso = "0.27" owo-colors = "4.1.0" oximeter = { path = "oximeter/oximeter" } diff --git a/common/src/api/external/mod.rs b/common/src/api/external/mod.rs index 8adb45beb50..87976a1c7fb 100644 --- a/common/src/api/external/mod.rs +++ b/common/src/api/external/mod.rs @@ -17,7 +17,7 @@ use anyhow::Context; use api_identity::ObjectIdentity; use chrono::DateTime; use chrono::Utc; -use daft::{leaf, Diffable}; +use daft::Diffable; use dropshot::HttpError; pub use dropshot::PaginationOrder; pub use error::*; @@ -758,11 +758,11 @@ impl From for i64 { PartialEq, PartialOrd, Serialize, + Diffable, )] +#[daft(leaf)] pub struct Generation(u64); -leaf!(Generation); - impl Generation { // `as` is a little distasteful because it allows lossy conversion, but we // know converting `i64::MAX` to `u64` will always succeed losslessly. @@ -1981,11 +1981,11 @@ impl JsonSchema for L4PortRange { Ord, SerializeDisplay, Hash, + Diffable, )] +#[daft(leaf)] pub struct MacAddr(pub macaddr::MacAddr6); -leaf!(MacAddr); - 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 diff --git a/common/src/zpool_name.rs b/common/src/zpool_name.rs index 39835935f00..44701d88245 100644 --- a/common/src/zpool_name.rs +++ b/common/src/zpool_name.rs @@ -5,7 +5,7 @@ //! Zpool labels and kinds shared between Nexus and Sled Agents use camino::{Utf8Path, Utf8PathBuf}; -use daft::{leaf, Diffable}; +use daft::Diffable; use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::{Deserialize, Deserializer, Serialize, Serializer}; @@ -39,14 +39,13 @@ 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, Diffable)] +#[daft(leaf)] pub struct ZpoolName { id: ZpoolUuid, kind: ZpoolKind, } -leaf!(ZpoolName); - const ZPOOL_NAME_REGEX: &str = r"^ox[ip]_[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$"; /// Custom JsonSchema implementation to encode the constraints on Name. diff --git a/nexus/reconfigurator/planning/src/planner.rs b/nexus/reconfigurator/planning/src/planner.rs index fc353d0c53c..3068d777c18 100644 --- a/nexus/reconfigurator/planning/src/planner.rs +++ b/nexus/reconfigurator/planning/src/planner.rs @@ -1010,7 +1010,7 @@ mod test { // No removed or modified zones on this sled let zones_cfg_diff = summary.zones_on_modified_sled(sled_id).unwrap(); assert!(zones_cfg_diff.zones.removed.is_empty()); - assert!(zones_cfg_diff.zones.modified.is_empty()); + assert_eq!(zones_cfg_diff.zones.modified().count(), 0); // 10 crucible zones addeed assert_eq!( *zones_cfg_diff.generation.after, @@ -1193,7 +1193,7 @@ mod test { .contains_key(sled_id)); let zones_cfg_diff = summary.zones_on_modified_sled(sled_id).unwrap(); - assert!(zones_cfg_diff.zones.modified.is_empty()); + assert_eq!(zones_cfg_diff.zones.modified().count(), 0); let zones_added = &zones_cfg_diff.zones.added; match zones_added.len() { n @ (3 | 4) => { @@ -1321,7 +1321,7 @@ mod test { let zones_diff = &summary.zones_on_modified_sled(&sled_id).unwrap().zones; assert!(zones_diff.removed.is_empty()); - assert!(zones_diff.modified.is_empty()); + assert_eq!(zones_diff.modified().count(), 0); let zones_added = &zones_diff.added; match zones_added.len() { 0 => {} @@ -1895,10 +1895,10 @@ mod test { DatasetKind::TransientZoneRoot, test_transient_zone_kind.clone(), ]); - for (_, sled_with_modified_datasets) in - &summary.diff.blueprint_datasets.modified + for (_, sled_with_modified_datasets) in &summary.modified_datasets_diff { - for (_, modified) in &sled_with_modified_datasets.datasets.modified + for modified in + sled_with_modified_datasets.datasets.modified_values_diff() { assert_eq!( *modified.disposition.before, @@ -1921,10 +1921,10 @@ mod test { assert!(expected_kinds.is_empty()); let (_zone_id, modified_zones) = - summary.diff.blueprint_zones.modified.iter().next().unwrap(); - assert_eq!(modified_zones.zones.modified.len(), 1); + summary.modified_zones_diff.iter().next().unwrap(); + assert_eq!(modified_zones.zones.modified().count(), 1); let (_, modified_zone) = - &modified_zones.zones.modified.first_key_value().unwrap(); + &modified_zones.zones.modified_diff().next().unwrap(); assert!( matches!(modified_zone.zone_type.before.kind(), ZoneKind::Crucible), "Expected the modified zone to be a Crucible zone, but it was: {:?}", @@ -2044,7 +2044,7 @@ mod test { assert_eq!(summary.total_zones_modified(), 6); let (_zone_id, zones_on_a_modified_sled) = - summary.diff.blueprint_zones.modified.iter().next().unwrap(); + summary.modified_zones_diff.iter().next().unwrap(); let added_zones = &zones_on_a_modified_sled.zones.added; assert_eq!(added_zones.len(), 1); for (_, zone) in added_zones { @@ -2052,10 +2052,11 @@ mod test { } assert_eq!( - zones_on_a_modified_sled.zones.modified.len(), + zones_on_a_modified_sled.zones.modified().count(), zones_using_zpool ); - for (_, modified_zone) in &zones_on_a_modified_sled.zones.modified { + for (_, modified_zone) in zones_on_a_modified_sled.zones.modified_diff() + { assert_eq!( *modified_zone.disposition.after, BlueprintZoneDisposition::Expunged, @@ -2380,7 +2381,7 @@ mod test { "for {desc}, generation should have been bumped" ); - for (_, modified_zone) in &modified_zones.zones.modified { + for modified_zone in modified_zones.zones.modified_values_diff() { assert_eq!( *modified_zone.disposition.after, BlueprintZoneDisposition::Expunged, diff --git a/nexus/types/src/deployment/blueprint_diff.rs b/nexus/types/src/deployment/blueprint_diff.rs index db75685cbd1..c43476a353b 100644 --- a/nexus/types/src/deployment/blueprint_diff.rs +++ b/nexus/types/src/deployment/blueprint_diff.rs @@ -40,6 +40,11 @@ pub struct BlueprintDiffSummary<'a> { pub before: &'a Blueprint, pub after: &'a Blueprint, pub diff: BlueprintDiff<'a>, + pub modified_zones_diff: BTreeMap>, + pub modified_disks_diff: + BTreeMap>, + pub modified_datasets_diff: + BTreeMap>, pub all_sleds: BTreeSet, pub sleds_added: BTreeSet, pub sleds_removed: BTreeSet, @@ -50,6 +55,23 @@ pub struct BlueprintDiffSummary<'a> { impl<'a> BlueprintDiffSummary<'a> { pub fn new(before: &'a Blueprint, after: &'a Blueprint) -> Self { let diff = before.diff(after); + + let modified_zones_diff = diff + .blueprint_zones + .modified_diff() + .map(|(k, v)| (*k, v)) + .collect(); + let modified_disks_diff = diff + .blueprint_disks + .modified_diff() + .map(|(k, v)| (*k, v)) + .collect(); + let modified_datasets_diff = diff + .blueprint_datasets + .modified_diff() + .map(|(k, v)| (*k, v)) + .collect(); + // We assume for now that sled_state additions represent sled additions. // Once we collapse the 4 blueprint maps this will be unambiguously // true. @@ -68,12 +90,12 @@ impl<'a> BlueprintDiffSummary<'a> { && diff.blueprint_datasets.removed.contains_key(sled_id)) || // Disks and datasets don't exist - (!diff.blueprint_disks.unchanged.contains_key(sled_id) + (!diff.blueprint_disks.is_unchanged(sled_id) && !diff.blueprint_disks.added.contains_key(sled_id) - && !diff.blueprint_disks.modified.contains_key(sled_id) - && !diff.blueprint_datasets.unchanged.contains_key(sled_id) + && !diff.blueprint_disks.is_modified(sled_id) + && !diff.blueprint_datasets.is_unchanged(sled_id) && !diff.blueprint_datasets.added.contains_key(sled_id) - && !diff.blueprint_datasets.modified.contains_key(sled_id) + && !diff.blueprint_datasets.is_modified(sled_id) ) }); @@ -87,20 +109,20 @@ impl<'a> BlueprintDiffSummary<'a> { // added, or removed disks or datasets at all on the given sled. If not, // we consider those sleds unchanged. let mut sleds_unchanged: BTreeSet<_> = - diff.blueprint_zones.unchanged.keys().map(|id| **id).collect(); + diff.blueprint_zones.unchanged_keys().map(|id| *id).collect(); sleds_unchanged.retain(|sled_id| { // Disks and datasets are unchanged - (diff.blueprint_disks.unchanged.contains_key(sled_id) - && diff.blueprint_datasets.unchanged.contains_key(sled_id)) || + (diff.blueprint_disks.is_unchanged(sled_id) + && diff.blueprint_datasets.is_unchanged(sled_id)) || // Disks and datasets don't exist (!diff.blueprint_disks.removed.contains_key(sled_id) && !diff.blueprint_disks.added.contains_key(sled_id) - && !diff.blueprint_disks.modified.contains_key(sled_id) + && !diff.blueprint_disks.is_modified(sled_id) && !diff.blueprint_datasets.removed.contains_key(sled_id) && !diff.blueprint_datasets.added.contains_key(sled_id) - && !diff.blueprint_datasets.modified.contains_key(sled_id) + && !diff.blueprint_datasets.is_modified(sled_id) ) }); @@ -112,12 +134,11 @@ impl<'a> BlueprintDiffSummary<'a> { // and datasets that are not in removed sleds. let mut sleds_modified: BTreeSet<_> = diff .sled_state - .modified - .keys() - .chain(diff.blueprint_zones.modified.keys()) - .chain(diff.blueprint_disks.modified.keys()) - .chain(diff.blueprint_datasets.modified.keys()) - .map(|k| **k) + .modified_keys() + .chain(diff.blueprint_zones.modified_keys()) + .chain(diff.blueprint_disks.modified_keys()) + .chain(diff.blueprint_datasets.modified_keys()) + .map(|k| *k) .collect(); for sled_id in diff .blueprint_disks @@ -142,6 +163,9 @@ impl<'a> BlueprintDiffSummary<'a> { before, after, diff, + modified_zones_diff, + modified_disks_diff, + modified_datasets_diff, all_sleds, sleds_added, sleds_removed, @@ -180,9 +204,7 @@ impl<'a> BlueprintDiffSummary<'a> { .values() .fold(0, |acc, c| acc + c.zones.len()) + self - .diff - .blueprint_zones - .modified + .modified_zones_diff .values() .fold(0, |acc, c| acc + c.zones.added.len()) } @@ -195,19 +217,15 @@ impl<'a> BlueprintDiffSummary<'a> { .values() .fold(0, |acc, c| acc + c.zones.len()) + self - .diff - .blueprint_zones - .modified + .modified_zones_diff .values() .fold(0, |acc, c| acc + c.zones.removed.len()) } /// The number of zones modified across all sleds pub fn total_zones_modified(&self) -> usize { - self.diff - .blueprint_zones - .modified + self.modified_zones_diff .values() - .fold(0, |acc, c| acc + c.zones.modified.len()) + .fold(0, |acc, c| acc + c.zones.modified().count()) } /// The number of disks added across all sleds @@ -218,9 +236,7 @@ impl<'a> BlueprintDiffSummary<'a> { .values() .fold(0, |acc, c| acc + c.disks.len()) + self - .diff - .blueprint_disks - .modified + .modified_disks_diff .values() .fold(0, |acc, c| acc + c.disks.added.len()) } @@ -233,19 +249,15 @@ impl<'a> BlueprintDiffSummary<'a> { .values() .fold(0, |acc, c| acc + c.disks.len()) + self - .diff - .blueprint_disks - .modified + .modified_disks_diff .values() .fold(0, |acc, c| acc + c.disks.removed.len()) } /// The number of disks modified across all sleds pub fn total_disks_modified(&self) -> usize { - self.diff - .blueprint_disks - .modified + self.modified_disks_diff .values() - .fold(0, |acc, c| acc + c.disks.modified.len()) + .fold(0, |acc, c| acc + c.disks.modified().count()) } /// The number of datasets added across all sleds @@ -256,9 +268,7 @@ impl<'a> BlueprintDiffSummary<'a> { .values() .fold(0, |acc, c| acc + c.datasets.len()) + self - .diff - .blueprint_datasets - .modified + .modified_datasets_diff .values() .fold(0, |acc, c| acc + c.datasets.added.len()) } @@ -271,43 +281,39 @@ impl<'a> BlueprintDiffSummary<'a> { .values() .fold(0, |acc, c| acc + c.datasets.len()) + self - .diff - .blueprint_datasets - .modified + .modified_datasets_diff .values() .fold(0, |acc, c| acc + c.datasets.removed.len()) } /// The number of datasets modified across all sleds pub fn total_datasets_modified(&self) -> usize { - self.diff - .blueprint_datasets - .modified + self.modified_datasets_diff .values() - .fold(0, |acc, c| acc + c.datasets.modified.len()) + .fold(0, |acc, c| acc + c.datasets.modified().count()) } /// Return the `BlueprintZonesConfigDiff` for a modified sled pub fn zones_on_modified_sled( &self, sled_id: &SledUuid, - ) -> Option<&'a BlueprintZonesConfigDiff> { - self.diff.blueprint_zones.modified.get(sled_id) + ) -> Option<&BlueprintZonesConfigDiff<'a>> { + self.modified_zones_diff.get(sled_id) } /// Return the `BlueprintDisksConfigDiff` for a modified sled pub fn disks_on_modified_sled( &self, sled_id: &SledUuid, - ) -> Option<&'a BlueprintPhysicalDisksConfigDiff> { - self.diff.blueprint_disks.modified.get(sled_id) + ) -> Option<&BlueprintPhysicalDisksConfigDiff<'a>> { + self.modified_disks_diff.get(sled_id) } /// Return the `BlueprintDatasetsConfigDiff` for a modified sled pub fn datasets_on_modified_sled( &self, sled_id: &SledUuid, - ) -> Option<&'a BlueprintDatasetsConfigDiff> { - self.diff.blueprint_datasets.modified.get(sled_id) + ) -> Option<&BlueprintDatasetsConfigDiff<'a>> { + self.modified_datasets_diff.get(sled_id) } /// Iterate over all added zones on a sled @@ -325,7 +331,7 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any added zones - let zones_cfg_diff = self.diff.blueprint_zones.modified.get(sled_id)?; + let zones_cfg_diff = self.modified_zones_diff.get(sled_id)?; if zones_cfg_diff.zones.added.is_empty() { return None; } @@ -355,7 +361,7 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any removed zones - let zones_cfg_diff = self.diff.blueprint_zones.modified.get(sled_id)?; + let zones_cfg_diff = self.modified_zones_diff.get(sled_id)?; if zones_cfg_diff.zones.removed.is_empty() { return None; } @@ -372,14 +378,16 @@ impl<'a> BlueprintDiffSummary<'a> { sled_id: &SledUuid, ) -> Option<(BpDiffZonesModified, BpDiffZoneErrors)> { // Then check if the sled is modified and there are any modified zones - let zones_cfg_diff = self.diff.blueprint_zones.modified.get(sled_id)?; - if zones_cfg_diff.zones.modified.is_empty() { + let zones_cfg_diff = self.modified_zones_diff.get(sled_id)?; + let mut modified_zones = + zones_cfg_diff.zones.modified_values_diff().peekable(); + if modified_zones.peek().is_none() { return None; } Some(BpDiffZonesModified::new( *zones_cfg_diff.generation.before, *zones_cfg_diff.generation.after, - zones_cfg_diff.zones.modified.values(), + modified_zones, )) } @@ -389,8 +397,8 @@ impl<'a> BlueprintDiffSummary<'a> { sled_id: &SledUuid, ) -> Option { // First check if the sled is unchanged - if let Some(&zones_cfg) = - self.diff.blueprint_zones.unchanged.get(sled_id) + if let Some(zones_cfg) = + self.diff.blueprint_zones.get_unchanged(sled_id) { if zones_cfg.zones.is_empty() { return None; @@ -403,14 +411,16 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any unchanged zones - let zones_cfg_diff = self.diff.blueprint_zones.modified.get(sled_id)?; - if zones_cfg_diff.zones.unchanged.is_empty() { + let zones_cfg_diff = self.modified_zones_diff.get(sled_id)?; + let mut unchanged_zones = + zones_cfg_diff.zones.unchanged_values().peekable(); + if unchanged_zones.peek().is_none() { return None; } Some(BpDiffZoneDetails::new( Some(*zones_cfg_diff.generation.before), Some(*zones_cfg_diff.generation.after), - zones_cfg_diff.zones.unchanged.values().map(|z| *z), + unchanged_zones, )) } @@ -432,7 +442,7 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any added disks - let disks_cfg_diff = self.diff.blueprint_disks.modified.get(sled_id)?; + let disks_cfg_diff = self.modified_disks_diff.get(sled_id)?; if disks_cfg_diff.disks.added.is_empty() { return None; } @@ -462,7 +472,7 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any removed disks - let disks_cfg_diff = self.diff.blueprint_disks.modified.get(sled_id)?; + let disks_cfg_diff = self.modified_disks_diff.get(sled_id)?; if disks_cfg_diff.disks.removed.is_empty() { return None; } @@ -479,8 +489,8 @@ impl<'a> BlueprintDiffSummary<'a> { sled_id: &SledUuid, ) -> Option { // First check if the sled is unchanged - if let Some(&disks_cfg) = - self.diff.blueprint_disks.unchanged.get(sled_id) + if let Some(disks_cfg) = + self.diff.blueprint_disks.get_unchanged(sled_id) { if disks_cfg.disks.is_empty() { return None; @@ -493,14 +503,16 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any unchanged disks - let disks_cfg_diff = self.diff.blueprint_disks.modified.get(sled_id)?; - if disks_cfg_diff.disks.unchanged.is_empty() { + let disks_cfg_diff = self.modified_disks_diff.get(sled_id)?; + let mut unchanged_disks = + disks_cfg_diff.disks.unchanged_values().peekable(); + if unchanged_disks.peek().is_none() { return None; } Some(DiffPhysicalDisksDetails::new( Some(*disks_cfg_diff.generation.before), Some(*disks_cfg_diff.generation.after), - disks_cfg_diff.disks.unchanged.values().map(|z| *z), + unchanged_disks, )) } @@ -524,8 +536,7 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any added datasets - let datasets_cfg_diff = - self.diff.blueprint_datasets.modified.get(sled_id)?; + let datasets_cfg_diff = self.modified_datasets_diff.get(sled_id)?; if datasets_cfg_diff.datasets.added.is_empty() { return None; } @@ -556,8 +567,7 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any removed datasets - let datasets_cfg_diff = - self.diff.blueprint_datasets.modified.get(sled_id)?; + let datasets_cfg_diff = self.modified_datasets_diff.get(sled_id)?; if datasets_cfg_diff.datasets.removed.is_empty() { return None; } @@ -574,8 +584,8 @@ impl<'a> BlueprintDiffSummary<'a> { sled_id: &SledUuid, ) -> Option { // First check if the sled is unchanged - if let Some(&datasets_cfg) = - self.diff.blueprint_datasets.unchanged.get(sled_id) + if let Some(datasets_cfg) = + self.diff.blueprint_datasets.get_unchanged(sled_id) { if datasets_cfg.datasets.is_empty() { return None; @@ -588,15 +598,16 @@ impl<'a> BlueprintDiffSummary<'a> { } // Then check if the sled is modified and there are any unchanged datasets - let datasets_cfg_diff = - self.diff.blueprint_datasets.modified.get(sled_id)?; - if datasets_cfg_diff.datasets.unchanged.is_empty() { + let datasets_cfg_diff = self.modified_datasets_diff.get(sled_id)?; + let mut unchanged_datasets = + datasets_cfg_diff.datasets.unchanged_values().peekable(); + if unchanged_datasets.peek().is_none() { return None; } Some(DiffDatasetsDetails::new( Some(*datasets_cfg_diff.generation.before), Some(*datasets_cfg_diff.generation.after), - datasets_cfg_diff.datasets.unchanged.values().map(|z| *z), + unchanged_datasets, )) } @@ -606,15 +617,16 @@ impl<'a> BlueprintDiffSummary<'a> { sled_id: &SledUuid, ) -> Option<(BpDiffDatasetsModified, BpDiffDatasetErrors)> { // Check if the sled is modified and there are any modified datasets - let datasets_cfg_diff = - self.diff.blueprint_datasets.modified.get(sled_id)?; - if datasets_cfg_diff.datasets.modified.is_empty() { + let datasets_cfg_diff = self.modified_datasets_diff.get(sled_id)?; + let mut modified_datasets = + datasets_cfg_diff.datasets.modified_values_diff().peekable(); + if modified_datasets.peek().is_none() { return None; } Some(BpDiffDatasetsModified::new( *datasets_cfg_diff.generation.before, *datasets_cfg_diff.generation.after, - datasets_cfg_diff.datasets.modified.values(), + modified_datasets, )) } } @@ -722,7 +734,7 @@ impl ModifiedZone { zone: BlueprintZoneConfig { disposition: *diff.disposition.after, id: *diff.id.after, - filesystem_pool: diff.filesystem_pool.after.clone(), + filesystem_pool: diff.filesystem_pool.after.cloned(), zone_type: diff.zone_type.after.clone(), }, }) @@ -748,12 +760,12 @@ impl BpDiffZonesModified { pub fn new<'a>( generation_before: Generation, generation_after: Generation, - zone_diffs: impl Iterator>, + zone_diffs: impl Iterator>, ) -> (BpDiffZonesModified, BpDiffZoneErrors) { let mut zones = vec![]; let mut errors = vec![]; for diff in zone_diffs { - match ModifiedZone::from_diff(diff) { + match ModifiedZone::from_diff(&diff) { Ok(modified_zone) => zones.push(modified_zone), Err(error) => errors.push(error), } @@ -1102,8 +1114,8 @@ impl ModifiedDataset { let prior_properties = ModifiableDatasetProperties { disposition: *disposition.before, - quota: *quota.before, - reservation: *reservation.before, + quota: quota.before.copied(), + reservation: reservation.before.copied(), compression: *compression.before, }; if pool.before != pool.after { @@ -1139,9 +1151,9 @@ impl ModifiedDataset { id: *id.after, pool: pool.after.clone(), kind: kind.after.clone(), - address: *address.after, - quota: *quota.after, - reservation: *reservation.after, + address: address.after.copied(), + quota: quota.after.copied(), + reservation: reservation.after.copied(), compression: *compression.after, }, }) @@ -1162,12 +1174,12 @@ impl BpDiffDatasetsModified { pub fn new<'a>( generation_before: Generation, generation_after: Generation, - dataset_diffs: impl Iterator>, + dataset_diffs: impl Iterator>, ) -> (BpDiffDatasetsModified, BpDiffDatasetErrors) { let mut datasets = vec![]; let mut errors = vec![]; for diff in dataset_diffs { - match ModifiedDataset::from_diff(diff) { + match ModifiedDataset::from_diff(&diff) { Ok(modified_zone) => datasets.push(modified_zone), Err(error) => errors.push(error), } @@ -1838,8 +1850,7 @@ impl<'diff> BlueprintDiffDisplay<'diff> { self.summary .diff .sled_state - .unchanged - .get(sled_id) + .get_unchanged(sled_id) .map(|before| before.to_string()) .unwrap_or("unknown".to_string()) } @@ -1853,11 +1864,11 @@ impl<'diff> BlueprintDiffDisplay<'diff> { } fn sled_state_modified(&self, sled_id: &SledUuid) -> String { let modified_sled_state = - self.summary.diff.sled_state.modified.get(sled_id); + self.summary.diff.sled_state.get_modified(sled_id); match modified_sled_state { None => { // The sled_state itself wasn't modified. It must be unchanged. - match self.summary.diff.sled_state.unchanged.get(sled_id) { + match self.summary.diff.sled_state.get_unchanged(sled_id) { Some(state) => { format!("{state}") }