From 3484a12cf2fe766a78043dc76eeb64a01ad6939d Mon Sep 17 00:00:00 2001 From: Rain Date: Sun, 14 Dec 2025 02:13:58 +0000 Subject: [PATCH 1/6] [spr] initial version Created using spr 1.3.6-beta.1 --- Cargo.lock | 5 +- .../omdb/src/bin/omdb/nexus/update_status.rs | 1 + dev-tools/reconfigurator-cli/src/lib.rs | 2 +- nexus/db-model/src/external_ip.rs | 2 +- nexus/db-model/src/inventory.rs | 1 + nexus/db-model/src/network_interface.rs | 2 +- .../deployment/external_networking.rs | 2 +- .../src/db/datastore/physical_disk.rs | 1 + nexus/db-queries/src/db/datastore/rack.rs | 1 + nexus/inventory/src/builder.rs | 1 + nexus/inventory/src/collector.rs | 3 + nexus/inventory/src/examples.rs | 1 + nexus/reconfigurator/execution/src/dns.rs | 1 + .../execution/src/omicron_zones.rs | 1 + .../planning/src/blueprint_builder/builder.rs | 2 + nexus/reconfigurator/planning/src/example.rs | 4 +- .../planning/src/mgs_updates/host_phase_1.rs | 1 + .../planning/src/mgs_updates/test_helpers.rs | 1 + nexus/reconfigurator/planning/src/planner.rs | 3 + .../planning/src/planner/image_source.rs | 2 +- .../src/planner/omicron_zone_placement.rs | 2 +- nexus/reconfigurator/planning/src/system.rs | 3 + .../tests/integration_tests/planner.rs | 3 + .../simulation/src/zone_images.rs | 17 +- .../background/tasks/sync_service_zone_nat.rs | 1 + nexus/test-utils/src/starter.rs | 1 + nexus/types/Cargo.toml | 1 + nexus/types/src/deployment.rs | 14 +- nexus/types/src/deployment/blueprint_diff.rs | 3 +- nexus/types/src/deployment/execution/utils.rs | 2 +- nexus/types/src/deployment/planning_input.rs | 3 +- nexus/types/src/deployment/planning_report.rs | 3 +- nexus/types/src/deployment/zone_type.rs | 8 +- nexus/types/src/internal_api/params.rs | 4 +- nexus/types/src/internal_api/views.rs | 11 +- nexus/types/src/inventory.rs | 23 +- nexus/types/src/inventory/display.rs | 5 +- sled-agent/config-reconciler/src/ledger.rs | 2 + .../config-reconciler/src/mupdate_override.rs | 2 + .../src/reconciler_task/datasets.rs | 1 + .../src/reconciler_task/zones.rs | 3 + sled-agent/src/bootstrap/server.rs | 2 +- sled-agent/src/rack_setup/plan/service.rs | 5 +- sled-agent/src/rack_setup/service.rs | 4 +- sled-agent/src/server.rs | 2 +- sled-agent/src/services.rs | 3 +- sled-agent/src/sim/sled_agent.rs | 9 +- sled-agent/src/sled_agent.rs | 4 +- sled-agent/types/Cargo.toml | 3 + sled-agent/types/src/disk.rs | 17 + sled-agent/types/src/instance.rs | 75 ++ sled-agent/types/src/inventory.rs | 931 ++++++++++++++++++ sled-agent/types/src/sled.rs | 35 + sled-agent/types/src/zone_bundle.rs | 36 + sled-agent/types/src/zone_images.rs | 2 + sled-agent/types/versions/Cargo.toml | 1 - .../inventory.rs | 344 +------ .../inventory.rs | 5 - sled-agent/types/versions/src/initial/disk.rs | 13 - .../types/versions/src/initial/instance.rs | 68 +- .../types/versions/src/initial/inventory.rs | 593 +---------- sled-agent/types/versions/src/initial/sled.rs | 27 +- sled-agent/types/versions/src/latest.rs | 1 - sled-agent/zone-images-examples/src/lib.rs | 2 +- sled-agent/zone-images/src/source_resolver.rs | 4 +- 65 files changed, 1226 insertions(+), 1109 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index efb21ff54ed..3bb38e31035 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7479,6 +7479,7 @@ dependencies = [ "serde", "serde_json", "serde_with", + "sled-agent-types", "sled-agent-types-versions", "sled-hardware-types", "slog", @@ -12926,12 +12927,15 @@ dependencies = [ "chrono", "daft", "iddqd", + "illumos-utils", + "indent_write", "omicron-common", "omicron-test-utils", "omicron-uuid-kinds", "omicron-workspace-hack", "oxnet", "propolis-client 0.1.0 (git+https://github.com/oxidecomputer/propolis?rev=3f1752e6cee9a2f8ecdce6e2ad3326781182e2d9)", + "propolis_api_types", "rcgen", "schemars 0.8.22", "serde", @@ -12961,7 +12965,6 @@ dependencies = [ "daft", "iddqd", "illumos-utils", - "indent_write", "omicron-common", "omicron-passwords", "omicron-test-utils", diff --git a/dev-tools/omdb/src/bin/omdb/nexus/update_status.rs b/dev-tools/omdb/src/bin/omdb/nexus/update_status.rs index d3401f39de5..185e6924997 100644 --- a/dev-tools/omdb/src/bin/omdb/nexus/update_status.rs +++ b/dev-tools/omdb/src/bin/omdb/nexus/update_status.rs @@ -20,6 +20,7 @@ use nexus_types::internal_api::views::{ }; use omicron_common::disk::M2Slot; use omicron_uuid_kinds::SledUuid; +use sled_agent_types::inventory::{OmicronZoneTypeExt, ZoneKindExt}; use strum::IntoEnumIterator; use tabled::Tabled; diff --git a/dev-tools/reconfigurator-cli/src/lib.rs b/dev-tools/reconfigurator-cli/src/lib.rs index 5f69431574a..c4db71e6628 100644 --- a/dev-tools/reconfigurator-cli/src/lib.rs +++ b/dev-tools/reconfigurator-cli/src/lib.rs @@ -67,7 +67,7 @@ use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::VnicUuid; use omicron_uuid_kinds::{BlueprintUuid, MupdateOverrideUuid}; use omicron_uuid_kinds::{CollectionUuid, MupdateUuid}; -use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::{ZoneKind, ZoneKindExt}; use slog_error_chain::InlineErrorChain; use std::borrow::Cow; use std::collections::BTreeSet; diff --git a/nexus/db-model/src/external_ip.rs b/nexus/db-model/src/external_ip.rs index 00a91029e69..26e0ce1307f 100644 --- a/nexus/db-model/src/external_ip.rs +++ b/nexus/db-model/src/external_ip.rs @@ -36,7 +36,7 @@ use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; use sled_agent_client::types::InstanceExternalIpBody; -use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::{ZoneKind, ZoneKindExt}; use slog_error_chain::SlogInlineError; use std::convert::TryFrom; use std::net::IpAddr; diff --git a/nexus/db-model/src/inventory.rs b/nexus/db-model/src/inventory.rs index 19d62285dd7..4ec6e2cfd23 100644 --- a/nexus/db-model/src/inventory.rs +++ b/nexus/db-model/src/inventory.rs @@ -91,6 +91,7 @@ use sled_agent_types::inventory::ZoneManifestNonBootInventory; use sled_agent_types::inventory::{ ConfigReconcilerInventoryResult, OmicronSledConfig, OmicronZoneConfig, OmicronZoneDataset, OmicronZoneImageSource, OmicronZoneType, + OmicronZoneTypeExt, }; use std::collections::BTreeSet; use std::net::{IpAddr, SocketAddrV6}; diff --git a/nexus/db-model/src/network_interface.rs b/nexus/db-model/src/network_interface.rs index 68eb8ec5ca7..33b649c5e9c 100644 --- a/nexus/db-model/src/network_interface.rs +++ b/nexus/db-model/src/network_interface.rs @@ -30,7 +30,7 @@ use omicron_uuid_kinds::VnicUuid; use oxnet::IpNet; use oxnet::Ipv4Net; use oxnet::Ipv6Net; -use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::{ZoneKind, ZoneKindExt}; use std::net::IpAddr; use uuid::Uuid; diff --git a/nexus/db-queries/src/db/datastore/deployment/external_networking.rs b/nexus/db-queries/src/db/datastore/deployment/external_networking.rs index f142f5e1715..e1fd676d568 100644 --- a/nexus/db-queries/src/db/datastore/deployment/external_networking.rs +++ b/nexus/db-queries/src/db/datastore/deployment/external_networking.rs @@ -27,7 +27,7 @@ use omicron_common::api::internal::shared::NetworkInterfaceKind; use omicron_common::api::internal::shared::PrivateIpConfig; use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::OmicronZoneUuid; -use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::{ZoneKind, ZoneKindExt}; use slog::Logger; use slog::debug; use slog::error; diff --git a/nexus/db-queries/src/db/datastore/physical_disk.rs b/nexus/db-queries/src/db/datastore/physical_disk.rs index ca1957e07d7..e9a6a7dfe63 100644 --- a/nexus/db-queries/src/db/datastore/physical_disk.rs +++ b/nexus/db-queries/src/db/datastore/physical_disk.rs @@ -348,6 +348,7 @@ mod test { use sled_agent_types::inventory::{ Baseboard, ConfigReconcilerInventoryStatus, Inventory, InventoryDisk, SledCpuFamily, SledRole, ZoneImageResolverInventory, + ZoneImageResolverInventoryExt, }; use std::num::NonZeroU32; diff --git a/nexus/db-queries/src/db/datastore/rack.rs b/nexus/db-queries/src/db/datastore/rack.rs index b51556e4b34..36da936db37 100644 --- a/nexus/db-queries/src/db/datastore/rack.rs +++ b/nexus/db-queries/src/db/datastore/rack.rs @@ -73,6 +73,7 @@ use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::SiloUserUuid; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; +use sled_agent_types::inventory::ZoneKindExt; use slog_error_chain::InlineErrorChain; use std::sync::{Arc, OnceLock}; use uuid::Uuid; diff --git a/nexus/inventory/src/builder.rs b/nexus/inventory/src/builder.rs index 83b893657a4..d8ce4b01f2a 100644 --- a/nexus/inventory/src/builder.rs +++ b/nexus/inventory/src/builder.rs @@ -41,6 +41,7 @@ use omicron_common::disk::M2Slot; use omicron_uuid_kinds::CollectionKind; use sled_agent_types::inventory::Baseboard; use sled_agent_types::inventory::Inventory; +use sled_agent_types::inventory::OmicronZoneTypeExt; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::hash::Hash; diff --git a/nexus/inventory/src/collector.rs b/nexus/inventory/src/collector.rs index 560f9021c58..83f5696f0af 100644 --- a/nexus/inventory/src/collector.rs +++ b/nexus/inventory/src/collector.rs @@ -24,6 +24,7 @@ use omicron_common::address::NTP_ADMIN_PORT; use omicron_common::disk::M2Slot; use omicron_uuid_kinds::OmicronZoneUuid; use sled_agent_types::inventory::OmicronZoneType; +use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::inventory::ZoneKind; use slog::Logger; use slog::o; @@ -735,7 +736,9 @@ mod test { use sled_agent_types::inventory::OmicronZoneConfig; use sled_agent_types::inventory::OmicronZoneImageSource; use sled_agent_types::inventory::OmicronZoneType; + use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::inventory::SledCpuFamily; + use sled_agent_types::inventory::ZoneKindExt; use slog::o; use std::net::Ipv6Addr; use std::net::SocketAddrV6; diff --git a/nexus/inventory/src/examples.rs b/nexus/inventory/src/examples.rs index 579c4519b35..45d2cc187ff 100644 --- a/nexus/inventory/src/examples.rs +++ b/nexus/inventory/src/examples.rs @@ -40,6 +40,7 @@ use sled_agent_types::inventory::Baseboard; use sled_agent_types::inventory::BootImageHeader; use sled_agent_types::inventory::BootPartitionDetails; use sled_agent_types::inventory::ConfigReconcilerInventory; +use sled_agent_types::inventory::ConfigReconcilerInventoryExt; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; use sled_agent_types::inventory::HostPhase2DesiredSlots; use sled_agent_types::inventory::Inventory; diff --git a/nexus/reconfigurator/execution/src/dns.rs b/nexus/reconfigurator/execution/src/dns.rs index 202188c2621..a6961172fb1 100644 --- a/nexus/reconfigurator/execution/src/dns.rs +++ b/nexus/reconfigurator/execution/src/dns.rs @@ -382,6 +382,7 @@ mod test { use sled_agent_types::inventory::OmicronZoneConfig; use sled_agent_types::inventory::OmicronZoneImageSource; use sled_agent_types::inventory::OmicronZoneType; + use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::inventory::SledRole; use sled_agent_types::inventory::ZoneKind; use std::collections::BTreeMap; diff --git a/nexus/reconfigurator/execution/src/omicron_zones.rs b/nexus/reconfigurator/execution/src/omicron_zones.rs index 2dfa9772faa..2f62036b955 100644 --- a/nexus/reconfigurator/execution/src/omicron_zones.rs +++ b/nexus/reconfigurator/execution/src/omicron_zones.rs @@ -23,6 +23,7 @@ use omicron_common::address::COCKROACH_ADMIN_PORT; use omicron_uuid_kinds::GenericUuid; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::SledUuid; +use sled_agent_types::inventory::ZoneKindExt; use slog::Logger; use slog::info; use slog::warn; diff --git a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs index 5aa042c4c92..b9457be5c17 100644 --- a/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs +++ b/nexus/reconfigurator/planning/src/blueprint_builder/builder.rs @@ -73,6 +73,7 @@ use omicron_uuid_kinds::ZpoolUuid; use sled_agent_types::inventory::MupdateOverrideBootInventory; use sled_agent_types::inventory::OmicronZoneDataset; use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use slog::Logger; use slog::debug; use slog::error; @@ -2577,6 +2578,7 @@ pub mod test { use nexus_types::external_api::views::SledPolicy; use omicron_common::address::IpRange; use omicron_test_utils::dev::test_setup_log; + use sled_agent_types::inventory::OmicronZoneTypeExt; use std::collections::BTreeSet; use std::mem; use tufaceous_artifact::ArtifactHash; diff --git a/nexus/reconfigurator/planning/src/example.rs b/nexus/reconfigurator/planning/src/example.rs index efd690b2815..7addbb1c811 100644 --- a/nexus/reconfigurator/planning/src/example.rs +++ b/nexus/reconfigurator/planning/src/example.rs @@ -1026,7 +1026,9 @@ mod tests { use omicron_common::address::get_sled_address; use omicron_common::api::external::Generation; use omicron_test_utils::dev::test_setup_log; - use sled_agent_types::inventory::{OmicronZoneConfig, ZoneKind}; + use sled_agent_types::inventory::{ + OmicronZoneConfig, OmicronZoneTypeExt, ZoneKind, + }; use slog_error_chain::InlineErrorChain; use super::*; diff --git a/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs b/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs index 43ae62bd272..5fd0b77f27a 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs @@ -22,6 +22,7 @@ use omicron_common::api::external::TufArtifactMeta; use omicron_common::api::external::TufRepoDescription; use omicron_common::disk::M2Slot; use omicron_uuid_kinds::SledUuid; +use sled_agent_types::inventory::BootPartitionContentsExt; use sled_hardware_types::OxideSled; use slog::Logger; use slog::debug; diff --git a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs index c934e51ab2b..0436e9071ac 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs @@ -47,6 +47,7 @@ use sled_agent_types::inventory::OmicronSledConfig; use sled_agent_types::inventory::SledCpuFamily; use sled_agent_types::inventory::SledRole; use sled_agent_types::inventory::ZoneImageResolverInventory; +use sled_agent_types::inventory::ZoneImageResolverInventoryExt; use sled_hardware_types::COSMO_SLED_MODEL; use sled_hardware_types::GIMLET_SLED_MODEL; use sled_hardware_types::OxideSled; diff --git a/nexus/reconfigurator/planning/src/planner.rs b/nexus/reconfigurator/planning/src/planner.rs index b12cbb8067d..152f8e17e45 100644 --- a/nexus/reconfigurator/planning/src/planner.rs +++ b/nexus/reconfigurator/planning/src/planner.rs @@ -62,10 +62,13 @@ use omicron_common::disk::M2Slot; use omicron_uuid_kinds::OmicronZoneUuid; use omicron_uuid_kinds::PhysicalDiskUuid; use omicron_uuid_kinds::SledUuid; +use sled_agent_types::inventory::ConfigReconcilerInventoryExt; use sled_agent_types::inventory::ConfigReconcilerInventoryResult; use sled_agent_types::inventory::OmicronZoneImageSource; use sled_agent_types::inventory::OmicronZoneType; +use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use slog::error; use slog::{Logger, info, o, warn}; use slog_error_chain::InlineErrorChain; diff --git a/nexus/reconfigurator/planning/src/planner/image_source.rs b/nexus/reconfigurator/planning/src/planner/image_source.rs index 8f6b3631b04..bbfee148c07 100644 --- a/nexus/reconfigurator/planning/src/planner/image_source.rs +++ b/nexus/reconfigurator/planning/src/planner/image_source.rs @@ -18,7 +18,7 @@ use nexus_types::{ use omicron_common::api::external::TufArtifactMeta; use omicron_uuid_kinds::{MupdateOverrideUuid, OmicronZoneUuid, SledUuid}; use sled_agent_types::inventory::{ - BootPartitionContents, BootPartitionDetails, ZoneKind, + BootPartitionContents, BootPartitionDetails, ZoneKind, ZoneKindExt, ZoneManifestBootInventory, }; use slog::{debug, info, o, warn}; diff --git a/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs b/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs index f39d7a5e895..56690446912 100644 --- a/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs +++ b/nexus/reconfigurator/planning/src/planner/omicron_zone_placement.rs @@ -6,7 +6,7 @@ use nexus_types::deployment::BlueprintZoneType; use omicron_uuid_kinds::SledUuid; -use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::{ZoneKind, ZoneKindExt}; use std::cmp::Ordering; use std::collections::BinaryHeap; use std::mem; diff --git a/nexus/reconfigurator/planning/src/system.rs b/nexus/reconfigurator/planning/src/system.rs index ea57a079da9..c616d309785 100644 --- a/nexus/reconfigurator/planning/src/system.rs +++ b/nexus/reconfigurator/planning/src/system.rs @@ -61,6 +61,7 @@ use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; use sled_agent_types::inventory::Baseboard; use sled_agent_types::inventory::ConfigReconcilerInventory; +use sled_agent_types::inventory::ConfigReconcilerInventoryExt; use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; use sled_agent_types::inventory::Inventory; use sled_agent_types::inventory::InventoryDataset; @@ -68,9 +69,11 @@ use sled_agent_types::inventory::InventoryDisk; use sled_agent_types::inventory::InventoryZpool; use sled_agent_types::inventory::MupdateOverrideBootInventory; use sled_agent_types::inventory::OmicronSledConfig; +use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::inventory::SledCpuFamily; use sled_agent_types::inventory::SledRole; use sled_agent_types::inventory::ZoneImageResolverInventory; +use sled_agent_types::inventory::ZoneImageResolverInventoryExt; use sled_agent_types::inventory::ZoneKind; use sled_agent_types::inventory::ZoneManifestBootInventory; use sled_hardware_types::GIMLET_SLED_MODEL; diff --git a/nexus/reconfigurator/planning/tests/integration_tests/planner.rs b/nexus/reconfigurator/planning/tests/integration_tests/planner.rs index b9a06e34100..cce5e7318b9 100644 --- a/nexus/reconfigurator/planning/tests/integration_tests/planner.rs +++ b/nexus/reconfigurator/planning/tests/integration_tests/planner.rs @@ -71,9 +71,12 @@ use oxnet::Ipv6Net; use reconfigurator_cli::test_utils::ReconfiguratorCliTestState; use semver::Version; use sled_agent_types::inventory::ConfigReconcilerInventory; +use sled_agent_types::inventory::ConfigReconcilerInventoryExt; use sled_agent_types::inventory::ConfigReconcilerInventoryResult; use sled_agent_types::inventory::OmicronZoneType; +use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use slog_error_chain::InlineErrorChain; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/nexus/reconfigurator/simulation/src/zone_images.rs b/nexus/reconfigurator/simulation/src/zone_images.rs index 3255ba5d2c0..873d35c6ebb 100644 --- a/nexus/reconfigurator/simulation/src/zone_images.rs +++ b/nexus/reconfigurator/simulation/src/zone_images.rs @@ -13,7 +13,8 @@ use omicron_common::{ api::external::TufRepoDescription, update::OmicronZoneManifestSource, }; use sled_agent_types::inventory::{ - ZoneArtifactInventory, ZoneKind, ZoneManifestBootInventory, + ZoneArtifactInventory, ZoneManifestBootInventory, + artifact_id_name_to_install_dataset_file, }; use swrite::{SWrite, swrite}; use tufaceous_artifact::KnownArtifactKind; @@ -87,10 +88,8 @@ impl SimTufRepoSource { } // Check that the zone name is known to ZoneKind. - if ZoneKind::artifact_id_name_to_install_dataset_file( - &artifact.id.name, - ) - .is_some() + if artifact_id_name_to_install_dataset_file(&artifact.id.name) + .is_some() { Some(artifact.id.name.clone()) } else { @@ -156,11 +155,9 @@ impl SimTufRepoSource { } let file_name = - ZoneKind::artifact_id_name_to_install_dataset_file( - &artifact.id.name, - ) - .expect("we checked this was Some at construction time") - .to_owned(); + artifact_id_name_to_install_dataset_file(&artifact.id.name) + .expect("we checked this was Some at construction time") + .to_owned(); let path = Utf8Path::new("/fake/path/install").join(&file_name); let status = if self.error_artifact_id_names.contains(&artifact.id.name) diff --git a/nexus/src/app/background/tasks/sync_service_zone_nat.rs b/nexus/src/app/background/tasks/sync_service_zone_nat.rs index 3483d439c20..33450e14c20 100644 --- a/nexus/src/app/background/tasks/sync_service_zone_nat.rs +++ b/nexus/src/app/background/tasks/sync_service_zone_nat.rs @@ -19,6 +19,7 @@ use nexus_db_queries::db::DataStore; use nexus_types::inventory::Collection; use omicron_common::address::{MAX_PORT, MIN_PORT}; use serde_json::json; +use sled_agent_types::inventory::ConfigReconcilerInventoryExt; use sled_agent_types::inventory::OmicronZoneType; use std::sync::Arc; use tokio::sync::watch; diff --git a/nexus/test-utils/src/starter.rs b/nexus/test-utils/src/starter.rs index 412959d3d63..bcbf228c410 100644 --- a/nexus/test-utils/src/starter.rs +++ b/nexus/test-utils/src/starter.rs @@ -97,6 +97,7 @@ use sled_agent_types::inventory::HostPhase2DesiredSlots; use sled_agent_types::inventory::OmicronSledConfig; use sled_agent_types::inventory::OmicronZoneDataset; use sled_agent_types::inventory::SledCpuFamily; +use sled_agent_types::inventory::ZoneKindExt; use sled_agent_types::rack_init::RecoverySiloConfig; use slog::{Logger, debug, error, o}; use std::collections::BTreeMap; diff --git a/nexus/types/Cargo.toml b/nexus/types/Cargo.toml index 973f7d0993f..7c575c37ecb 100644 --- a/nexus/types/Cargo.toml +++ b/nexus/types/Cargo.toml @@ -66,6 +66,7 @@ omicron-common.workspace = true omicron-passwords.workspace = true omicron-workspace-hack.workspace = true semver.workspace = true +sled-agent-types.workspace = true sled-agent-types-versions.workspace = true swrite.workspace = true tough.workspace = true diff --git a/nexus/types/src/deployment.rs b/nexus/types/src/deployment.rs index 52a61e35623..ea0adef1a02 100644 --- a/nexus/types/src/deployment.rs +++ b/nexus/types/src/deployment.rs @@ -51,12 +51,14 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; -use sled_agent_types_versions::latest::inventory::HostPhase2DesiredContents; -use sled_agent_types_versions::latest::inventory::HostPhase2DesiredSlots; -use sled_agent_types_versions::latest::inventory::OmicronSledConfig; -use sled_agent_types_versions::latest::inventory::OmicronZoneConfig; -use sled_agent_types_versions::latest::inventory::OmicronZoneImageSource; -use sled_agent_types_versions::latest::inventory::ZoneKind; +use sled_agent_types::inventory::HostPhase2DesiredContents; +use sled_agent_types::inventory::HostPhase2DesiredSlots; +use sled_agent_types::inventory::OmicronSledConfig; +use sled_agent_types::inventory::OmicronZoneConfig; +use sled_agent_types::inventory::OmicronZoneImageSource; +use sled_agent_types::inventory::OmicronZoneTypeExt; +use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use slog::Key; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/nexus/types/src/deployment/blueprint_diff.rs b/nexus/types/src/deployment/blueprint_diff.rs index b2966e18569..eb14a96efe0 100644 --- a/nexus/types/src/deployment/blueprint_diff.rs +++ b/nexus/types/src/deployment/blueprint_diff.rs @@ -25,7 +25,8 @@ use omicron_common::api::external::ByteCount; use omicron_common::disk::{CompressionAlgorithm, DatasetName}; use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::{DatasetUuid, OmicronZoneUuid, PhysicalDiskUuid}; -use sled_agent_types_versions::latest::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use std::collections::{BTreeMap, BTreeSet}; use std::fmt::{self, Write as _}; diff --git a/nexus/types/src/deployment/execution/utils.rs b/nexus/types/src/deployment/execution/utils.rs index fd6bb3f87b3..8084ded0fad 100644 --- a/nexus/types/src/deployment/execution/utils.rs +++ b/nexus/types/src/deployment/execution/utils.rs @@ -10,7 +10,7 @@ use omicron_common::{ api::external::Generation, }; use omicron_uuid_kinds::SledUuid; -use sled_agent_types_versions::latest::inventory::SledRole; +use sled_agent_types::inventory::SledRole; use crate::{ deployment::{ diff --git a/nexus/types/src/deployment/planning_input.rs b/nexus/types/src/deployment/planning_input.rs index 3b38e748b6b..0425af80001 100644 --- a/nexus/types/src/deployment/planning_input.rs +++ b/nexus/types/src/deployment/planning_input.rs @@ -42,7 +42,8 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; -use sled_agent_types_versions::latest::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::collections::btree_map::Entry; diff --git a/nexus/types/src/deployment/planning_report.rs b/nexus/types/src/deployment/planning_report.rs index 2d260f857ed..8888461cef5 100644 --- a/nexus/types/src/deployment/planning_report.rs +++ b/nexus/types/src/deployment/planning_report.rs @@ -30,7 +30,8 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; -use sled_agent_types_versions::latest::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use slog_error_chain::InlineErrorChain; use std::collections::BTreeMap; use std::collections::BTreeSet; diff --git a/nexus/types/src/deployment/zone_type.rs b/nexus/types/src/deployment/zone_type.rs index 3dcc80919ff..4013ab18980 100644 --- a/nexus/types/src/deployment/zone_type.rs +++ b/nexus/types/src/deployment/zone_type.rs @@ -16,9 +16,9 @@ use omicron_common::disk::DatasetName; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; -use sled_agent_types_versions::latest::inventory::OmicronZoneDataset; -use sled_agent_types_versions::latest::inventory::OmicronZoneType; -use sled_agent_types_versions::latest::inventory::ZoneKind; +use sled_agent_types::inventory::OmicronZoneDataset; +use sled_agent_types::inventory::OmicronZoneType; +use sled_agent_types::inventory::ZoneKind; use std::net::Ipv6Addr; #[derive( @@ -348,7 +348,7 @@ pub mod blueprint_zone_type { use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; - use sled_agent_types_versions::latest::inventory::OmicronZoneDataset; + use sled_agent_types::inventory::OmicronZoneDataset; use std::net::IpAddr; use std::net::Ipv6Addr; use std::net::SocketAddrV6; diff --git a/nexus/types/src/internal_api/params.rs b/nexus/types/src/internal_api/params.rs index f21f46027de..d245306ea35 100644 --- a/nexus/types/src/internal_api/params.rs +++ b/nexus/types/src/internal_api/params.rs @@ -23,8 +23,8 @@ use omicron_uuid_kinds::SledUuid; use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use sled_agent_types_versions::latest::inventory::{SledCpuFamily, SledRole}; -use sled_agent_types_versions::latest::rack_init::RecoverySiloConfig; +use sled_agent_types::inventory::{SledCpuFamily, SledRole}; +use sled_agent_types::rack_init::RecoverySiloConfig; use std::fmt; use std::net::IpAddr; use std::net::SocketAddr; diff --git a/nexus/types/src/internal_api/views.rs b/nexus/types/src/internal_api/views.rs index e9ed52ad728..22a7c76bc0f 100644 --- a/nexus/types/src/internal_api/views.rs +++ b/nexus/types/src/internal_api/views.rs @@ -31,11 +31,12 @@ use schemars::JsonSchema; use semver::Version; use serde::Deserialize; use serde::Serialize; -use sled_agent_types_versions::latest::inventory::BootPartitionContents; -use sled_agent_types_versions::latest::inventory::BootPartitionDetails; -use sled_agent_types_versions::latest::inventory::ConfigReconcilerInventoryResult; -use sled_agent_types_versions::latest::inventory::OmicronZoneImageSource; -use sled_agent_types_versions::latest::inventory::OmicronZoneType; +use sled_agent_types::inventory::BootPartitionContents; +use sled_agent_types::inventory::BootPartitionDetails; +use sled_agent_types::inventory::ConfigReconcilerInventoryExt; +use sled_agent_types::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types::inventory::OmicronZoneImageSource; +use sled_agent_types::inventory::OmicronZoneType; use std::collections::BTreeMap; use std::collections::VecDeque; use std::fmt::Display; diff --git a/nexus/types/src/inventory.rs b/nexus/types/src/inventory.rs index b95527e2d06..76233ff74b5 100644 --- a/nexus/types/src/inventory.rs +++ b/nexus/types/src/inventory.rs @@ -36,17 +36,18 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use sled_agent_types_versions::latest::inventory::ConfigReconcilerInventory; -use sled_agent_types_versions::latest::inventory::ConfigReconcilerInventoryResult; -use sled_agent_types_versions::latest::inventory::ConfigReconcilerInventoryStatus; -use sled_agent_types_versions::latest::inventory::InventoryDataset; -use sled_agent_types_versions::latest::inventory::InventoryDisk; -use sled_agent_types_versions::latest::inventory::InventoryZpool; -use sled_agent_types_versions::latest::inventory::OmicronSledConfig; -use sled_agent_types_versions::latest::inventory::OmicronZoneConfig; -use sled_agent_types_versions::latest::inventory::SledCpuFamily; -use sled_agent_types_versions::latest::inventory::SledRole; -use sled_agent_types_versions::latest::inventory::ZoneImageResolverInventory; +use sled_agent_types::inventory::ConfigReconcilerInventory; +use sled_agent_types::inventory::ConfigReconcilerInventoryExt; +use sled_agent_types::inventory::ConfigReconcilerInventoryResult; +use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; +use sled_agent_types::inventory::InventoryDataset; +use sled_agent_types::inventory::InventoryDisk; +use sled_agent_types::inventory::InventoryZpool; +use sled_agent_types::inventory::OmicronSledConfig; +use sled_agent_types::inventory::OmicronZoneConfig; +use sled_agent_types::inventory::SledCpuFamily; +use sled_agent_types::inventory::SledRole; +use sled_agent_types::inventory::ZoneImageResolverInventory; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::net::SocketAddrV6; diff --git a/nexus/types/src/inventory/display.rs b/nexus/types/src/inventory/display.rs index d220d876fd8..67d0fac3a3a 100644 --- a/nexus/types/src/inventory/display.rs +++ b/nexus/types/src/inventory/display.rs @@ -20,7 +20,10 @@ use omicron_common::disk::M2Slot; use omicron_uuid_kinds::{ DatasetUuid, OmicronZoneUuid, PhysicalDiskUuid, ZpoolUuid, }; -use sled_agent_types_versions::latest::inventory::{ +use sled_agent_types::inventory::OmicronZoneTypeExt; +use sled_agent_types::inventory::ZoneImageResolverInventoryExt; +use sled_agent_types::inventory::ZoneKindExt; +use sled_agent_types::inventory::{ BootImageHeader, BootPartitionContents, BootPartitionDetails, ConfigReconcilerInventory, ConfigReconcilerInventoryResult, ConfigReconcilerInventoryStatus, HostPhase2DesiredContents, diff --git a/sled-agent/config-reconciler/src/ledger.rs b/sled-agent/config-reconciler/src/ledger.rs index f47e7d01081..c2bdafa1a8b 100644 --- a/sled-agent/config-reconciler/src/ledger.rs +++ b/sled-agent/config-reconciler/src/ledger.rs @@ -11,9 +11,11 @@ use omicron_common::api::external::Generation; use omicron_common::ledger; use omicron_common::ledger::Ledger; use sled_agent_types::artifact::ArtifactConfig; +use sled_agent_types::inventory::HostPhase2DesiredContentsExt; use sled_agent_types::inventory::HostPhase2DesiredSlots; use sled_agent_types::inventory::OmicronSledConfig; use sled_agent_types::inventory::OmicronZoneImageSource; +use sled_agent_types::inventory::OmicronZoneImageSourceExt; use slog::Logger; use slog::error; use slog::info; diff --git a/sled-agent/config-reconciler/src/mupdate_override.rs b/sled-agent/config-reconciler/src/mupdate_override.rs index 633e9332b9a..490658f1e12 100644 --- a/sled-agent/config-reconciler/src/mupdate_override.rs +++ b/sled-agent/config-reconciler/src/mupdate_override.rs @@ -11,7 +11,9 @@ use omicron_common::zone_images::ZoneImageFileSource; use sled_agent_types::inventory::HostPhase2DesiredContents; use sled_agent_types::inventory::OmicronZoneConfig; use sled_agent_types::inventory::OmicronZoneImageSource; +use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::ZoneKindExt; use sled_agent_types::zone_images::OmicronZoneFileSource; use sled_agent_types::zone_images::OmicronZoneImageLocation; use sled_agent_types::zone_images::PreparedOmicronZone; diff --git a/sled-agent/config-reconciler/src/reconciler_task/datasets.rs b/sled-agent/config-reconciler/src/reconciler_task/datasets.rs index 2cae109c382..4fe9a84a2e2 100644 --- a/sled-agent/config-reconciler/src/reconciler_task/datasets.rs +++ b/sled-agent/config-reconciler/src/reconciler_task/datasets.rs @@ -26,6 +26,7 @@ use omicron_common::disk::DatasetName; use omicron_uuid_kinds::DatasetUuid; use sled_agent_types::inventory::ConfigReconcilerInventoryResult; use sled_agent_types::inventory::OmicronZoneConfig; +use sled_agent_types::inventory::OmicronZoneConfigExt; use sled_agent_types::inventory::OrphanedDataset; use sled_storage::config::MountConfig; use sled_storage::dataset::ZONE_DATASET; diff --git a/sled-agent/config-reconciler/src/reconciler_task/zones.rs b/sled-agent/config-reconciler/src/reconciler_task/zones.rs index 7a2e02b4e60..f07acb7989a 100644 --- a/sled-agent/config-reconciler/src/reconciler_task/zones.rs +++ b/sled-agent/config-reconciler/src/reconciler_task/zones.rs @@ -30,7 +30,9 @@ use omicron_common::address::Ipv6Subnet; use omicron_uuid_kinds::OmicronZoneUuid; use sled_agent_types::inventory::ConfigReconcilerInventoryResult; use sled_agent_types::inventory::OmicronZoneConfig; +use sled_agent_types::inventory::OmicronZoneConfigExt; use sled_agent_types::inventory::OmicronZoneType; +use sled_agent_types::inventory::OmicronZoneTypeExt; use sled_agent_types::zone_images::MupdateOverrideReadError; use sled_agent_types::zone_images::OmicronZoneImageLocation; use sled_agent_types::zone_images::PreparedOmicronZone; @@ -1295,6 +1297,7 @@ mod tests { use sled_agent_types::inventory::OmicronZoneDataset; use sled_agent_types::inventory::OmicronZoneImageSource; use sled_agent_types::inventory::ZoneKind; + use sled_agent_types::inventory::ZoneKindExt; use sled_agent_types::zone_images::MupdateOverrideStatus; use sled_agent_types::zone_images::OmicronZoneFileSource; use sled_agent_types::zone_images::RemoveMupdateOverrideBootSuccess; diff --git a/sled-agent/src/bootstrap/server.rs b/sled-agent/src/bootstrap/server.rs index be4cd24bf0e..f8d43cb91b4 100644 --- a/sled-agent/src/bootstrap/server.rs +++ b/sled-agent/src/bootstrap/server.rs @@ -42,7 +42,7 @@ use omicron_uuid_kinds::RackInitUuid; use sled_agent_config_reconciler::ConfigReconcilerSpawnToken; use sled_agent_config_reconciler::InternalDisksReceiver; use sled_agent_types::rack_init::RackInitializeRequestParams; -use sled_agent_types::sled::StartSledAgentRequest; +use sled_agent_types::sled::{StartSledAgentRequest, StartSledAgentRequestExt}; use sled_hardware::underlay; use sled_storage::dataset::CONFIG_DATASET; use slog::Logger; diff --git a/sled-agent/src/rack_setup/plan/service.rs b/sled-agent/src/rack_setup/plan/service.rs index f511f1de056..45a55b85448 100644 --- a/sled-agent/src/rack_setup/plan/service.rs +++ b/sled-agent/src/rack_setup/plan/service.rs @@ -60,7 +60,9 @@ use serde::{Deserialize, Serialize}; use sled_agent_client::{ Client as SledAgentClient, Error as SledAgentError, types as SledAgentTypes, }; -use sled_agent_types::inventory::{Inventory, OmicronZoneDataset, SledRole}; +use sled_agent_types::inventory::{ + Inventory, OmicronZoneDataset, SledRole, ZoneKindExt, +}; use sled_agent_types::rack_init::RackInitializeRequest as Config; use sled_agent_types::sled::StartSledAgentRequest; use slog::Logger; @@ -1307,6 +1309,7 @@ mod tests { use sled_agent_types::inventory::ConfigReconcilerInventoryStatus; use sled_agent_types::inventory::SledCpuFamily; use sled_agent_types::inventory::ZoneImageResolverInventory; + use sled_agent_types::inventory::ZoneImageResolverInventoryExt; use sled_agent_types::rack_init::BootstrapAddressDiscovery; use sled_agent_types::rack_init::RecoverySiloConfig; use sled_hardware_types::Baseboard; diff --git a/sled-agent/src/rack_setup/service.rs b/sled-agent/src/rack_setup/service.rs index efc282eeb4a..edffc5ee6d8 100644 --- a/sled-agent/src/rack_setup/service.rs +++ b/sled-agent/src/rack_setup/service.rs @@ -112,6 +112,7 @@ use sled_agent_types::early_networking::{ use sled_agent_types::inventory::{ ConfigReconcilerInventoryResult, HostPhase2DesiredSlots, OmicronSledConfig, OmicronZoneConfig, OmicronZoneType, OmicronZonesConfig, + ZONES_CONFIG_INITIAL_GENERATION, }; use sled_agent_types::rack_init::{ BootstrapAddressDiscovery, RackInitializeRequest as Config, @@ -1616,7 +1617,7 @@ async fn init_trust_quorum( struct DeployStepVersion; impl DeployStepVersion { - const V1_NOTHING: Generation = OmicronZonesConfig::INITIAL_GENERATION; + const V1_NOTHING: Generation = ZONES_CONFIG_INITIAL_GENERATION; const V2_DNS_ONLY: Generation = Self::V1_NOTHING.next(); const V3_DNS_AND_NTP: Generation = Self::V2_DNS_ONLY.next(); const V4_COCKROACHDB: Generation = Self::V3_DNS_AND_NTP.next(); @@ -1732,6 +1733,7 @@ mod test { use sled_agent_types::inventory::{ Baseboard, ConfigReconcilerInventoryStatus, Inventory, InventoryDisk, OmicronZoneType, SledCpuFamily, SledRole, ZoneImageResolverInventory, + ZoneImageResolverInventoryExt, }; fn make_sled_info( diff --git a/sled-agent/src/server.rs b/sled-agent/src/server.rs index 31fa6bfbceb..a6b2cf83aa8 100644 --- a/sled-agent/src/server.rs +++ b/sled-agent/src/server.rs @@ -13,7 +13,7 @@ use crate::services::ServiceManager; use internal_dns_resolver::Resolver; use omicron_uuid_kinds::SledUuid; use sled_agent_config_reconciler::ConfigReconcilerSpawnToken; -use sled_agent_types::sled::StartSledAgentRequest; +use sled_agent_types::sled::{StartSledAgentRequest, StartSledAgentRequestExt}; use slog::Logger; use std::net::SocketAddr; use std::sync::Arc; diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index a240558317c..c7eaf5c97aa 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -90,7 +90,8 @@ use omicron_common::disk::{DatasetKind, DatasetName}; use omicron_ddm_admin_client::DdmError; use omicron_uuid_kinds::OmicronZoneUuid; use sled_agent_types::inventory::{ - OmicronZoneConfig, OmicronZoneType, ZoneKind, + OmicronZoneConfig, OmicronZoneConfigExt, OmicronZoneType, + OmicronZoneTypeExt, ZoneKind, ZoneKindExt, }; use sled_agent_types::sled::SWITCH_ZONE_BASEBOARD_FILE; use sled_agent_types::zone_images::{ diff --git a/sled-agent/src/sim/sled_agent.rs b/sled-agent/src/sim/sled_agent.rs index d9d731bffd6..fcfcce59f1c 100644 --- a/sled-agent/src/sim/sled_agent.rs +++ b/sled-agent/src/sim/sled_agent.rs @@ -60,10 +60,11 @@ use sled_agent_types::instance::{ VmmPutStateResponse, VmmSpecExt, VmmStateRequested, VmmUnregisterResponse, }; use sled_agent_types::inventory::{ - ConfigReconcilerInventory, ConfigReconcilerInventoryStatus, - HostPhase2DesiredSlots, Inventory, InventoryDataset, InventoryDisk, - InventoryZpool, OmicronSledConfig, OmicronZonesConfig, SledRole, - ZoneImageResolverInventory, + ConfigReconcilerInventory, ConfigReconcilerInventoryExt, + ConfigReconcilerInventoryStatus, HostPhase2DesiredSlots, Inventory, + InventoryDataset, InventoryDisk, InventoryZpool, OmicronSledConfig, + OmicronZonesConfig, SledRole, ZoneImageResolverInventory, + ZoneImageResolverInventoryExt, }; use sled_agent_types::support_bundle::SupportBundleMetadata; diff --git a/sled-agent/src/sled_agent.rs b/sled-agent/src/sled_agent.rs index 25bc71f0ef6..bc726a423df 100644 --- a/sled-agent/src/sled_agent.rs +++ b/sled-agent/src/sled_agent.rs @@ -74,7 +74,9 @@ use sled_agent_types::instance::{ }; use sled_agent_types::inventory::{Inventory, OmicronSledConfig, SledRole}; use sled_agent_types::probes::ProbeCreate; -use sled_agent_types::sled::{BaseboardId, StartSledAgentRequest}; +use sled_agent_types::sled::{ + BaseboardId, StartSledAgentRequest, StartSledAgentRequestExt, +}; use sled_agent_types::zone_bundle::{ BundleUtilization, CleanupContext, CleanupCount, CleanupPeriod, PriorityOrder, StorageLimit, ZoneBundleMetadata, diff --git a/sled-agent/types/Cargo.toml b/sled-agent/types/Cargo.toml index c0f1dc38b3c..208963ca312 100644 --- a/sled-agent/types/Cargo.toml +++ b/sled-agent/types/Cargo.toml @@ -15,11 +15,14 @@ camino.workspace = true chrono.workspace = true daft.workspace = true iddqd.workspace = true +illumos-utils.workspace = true +indent_write.workspace = true omicron-common.workspace = true omicron-uuid-kinds.workspace = true omicron-workspace-hack.workspace = true oxnet.workspace = true propolis-client.workspace = true +propolis_api_types.workspace = true schemars.workspace = true serde.workspace = true serde_human_bytes.workspace = true diff --git a/sled-agent/types/src/disk.rs b/sled-agent/types/src/disk.rs index dc3bfc212ab..e35637c747b 100644 --- a/sled-agent/types/src/disk.rs +++ b/sled-agent/types/src/disk.rs @@ -5,3 +5,20 @@ //! Disk types for sled-agent. pub use sled_agent_types_versions::latest::disk::*; + +/// Extension trait for [`DiskStateRequested`]. +pub trait DiskStateRequestedExt { + /// Returns whether the requested state is attached to an Instance or not. + fn is_attached(&self) -> bool; +} + +impl DiskStateRequestedExt for DiskStateRequested { + fn is_attached(&self) -> bool { + match self { + DiskStateRequested::Detached => false, + DiskStateRequested::Destroyed => false, + DiskStateRequested::Faulted => false, + DiskStateRequested::Attached(_) => true, + } + } +} diff --git a/sled-agent/types/src/instance.rs b/sled-agent/types/src/instance.rs index 843e7cd9532..6c66e375c4c 100644 --- a/sled-agent/types/src/instance.rs +++ b/sled-agent/types/src/instance.rs @@ -4,4 +4,79 @@ //! Common instance-related types. +use propolis_api_types::instance_spec::{ + SpecKey, + components::backends::{ + CrucibleStorageBackend, FileStorageBackend, VirtioNetworkBackend, + }, + v0::ComponentV0, +}; + pub use sled_agent_types_versions::latest::instance::*; + +/// Extension trait for [`VmmSpec`] to provide helper methods. +pub trait VmmSpecExt { + fn crucible_backends( + &self, + ) -> impl Iterator; + + fn viona_backends( + &self, + ) -> impl Iterator; + + fn file_backends( + &self, + ) -> impl Iterator; +} + +impl VmmSpecExt for VmmSpec { + fn crucible_backends( + &self, + ) -> impl Iterator { + self.0.components.iter().filter_map( + |(key, component)| match component { + ComponentV0::CrucibleStorageBackend(be) => Some((key, be)), + _ => None, + }, + ) + } + + fn viona_backends( + &self, + ) -> impl Iterator { + self.0.components.iter().filter_map( + |(key, component)| match component { + ComponentV0::VirtioNetworkBackend(be) => Some((key, be)), + _ => None, + }, + ) + } + + fn file_backends( + &self, + ) -> impl Iterator { + self.0.components.iter().filter_map( + |(key, component)| match component { + ComponentV0::FileStorageBackend(be) => Some((key, be)), + _ => None, + }, + ) + } +} + +/// Extension trait for [`VmmStateRequested`]. +pub trait VmmStateRequestedExt { + /// Returns true if the state represents a stopped Instance. + fn is_stopped(&self) -> bool; +} + +impl VmmStateRequestedExt for VmmStateRequested { + fn is_stopped(&self) -> bool { + match self { + VmmStateRequested::MigrationTarget(_) => false, + VmmStateRequested::Running => false, + VmmStateRequested::Stopped => true, + VmmStateRequested::Reboot => false, + } + } +} diff --git a/sled-agent/types/src/inventory.rs b/sled-agent/types/src/inventory.rs index 185a52945e9..497be890077 100644 --- a/sled-agent/types/src/inventory.rs +++ b/sled-agent/types/src/inventory.rs @@ -4,4 +4,935 @@ //! Sled-agent types for inventory. +use std::collections::BTreeMap; +use std::fmt::{self, Write}; +use std::net::{IpAddr, Ipv6Addr}; + +use camino::Utf8PathBuf; +use iddqd::IdOrdMap; +use indent_write::fmt::IndentWriter; +use omicron_common::api::external::Generation; +use omicron_common::disk::{DatasetKind, DatasetName, M2Slot}; +use omicron_common::update::{ArtifactId, OmicronZoneManifestSource}; +use omicron_uuid_kinds::MupdateUuid; +use tufaceous_artifact::{ArtifactHash, KnownArtifactKind}; + pub use sled_agent_types_versions::latest::inventory::*; + +/// Generation 1 of `OmicronZonesConfig` is always the set of no zones. +pub const ZONES_CONFIG_INITIAL_GENERATION: Generation = Generation::from_u32(1); + +/// The NTP prefix used for both BoundaryNtp and InternalNtp zones and services. +pub const NTP_PREFIX: &str = "ntp"; + +pub trait ZoneKindExt { + /// Return a string that is used to construct **zone names**. This string + /// is guaranteed to be stable over time. + fn zone_prefix(self) -> &'static str; + + /// Return a string that identifies **zone image filenames** in the install + /// dataset. + /// + /// This method is exactly equivalent to `format!("{}.tar.gz", + /// self.zone_prefix())`, but returns `&'static str`s. A unit test ensures + /// they stay consistent. + fn artifact_in_install_dataset(self) -> &'static str; + + /// Return a string that is used to construct **SMF service names**. This + /// string is guaranteed to be stable over time. + fn service_prefix(self) -> &'static str; + + /// Return a string suitable for use **in `Name` instances**. This string + /// is guaranteed to be stable over time. + /// + /// This string uses dashes rather than underscores, as required by `Name`. + fn name_prefix(self) -> &'static str; + + /// Return a string that is used for reporting and error messages. This is + /// **not guaranteed** to be stable. + /// + /// If you're displaying a user-friendly message, prefer this method. + fn report_str(self) -> &'static str; + + /// Return a string used as an artifact name for control-plane zones. + /// This is **not guaranteed** to be stable. + /// + /// These strings match the `ArtifactId::name`s Nexus constructs when + /// unpacking the composite control-plane artifact in a TUF repo. Currently, + /// these are chosen by reading the `pkg` value of the `oxide.json` object + /// inside each zone image tarball. + fn artifact_id_name(self) -> &'static str; + + /// Return true if an artifact represents a control plane zone image + /// of this kind. + fn is_control_plane_zone_artifact(self, artifact_id: &ArtifactId) -> bool; +} + +impl ZoneKindExt for ZoneKind { + fn zone_prefix(self) -> &'static str { + match self { + ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => NTP_PREFIX, + ZoneKind::Clickhouse => "clickhouse", + ZoneKind::ClickhouseKeeper => "clickhouse_keeper", + ZoneKind::ClickhouseServer => "clickhouse_server", + ZoneKind::CockroachDb => "cockroachdb", + ZoneKind::Crucible => "crucible", + ZoneKind::CruciblePantry => "crucible_pantry", + ZoneKind::ExternalDns => "external_dns", + ZoneKind::InternalDns => "internal_dns", + ZoneKind::Nexus => "nexus", + ZoneKind::Oximeter => "oximeter", + } + } + + fn artifact_in_install_dataset(self) -> &'static str { + match self { + ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => "ntp.tar.gz", + ZoneKind::Clickhouse => "clickhouse.tar.gz", + ZoneKind::ClickhouseKeeper => "clickhouse_keeper.tar.gz", + ZoneKind::ClickhouseServer => "clickhouse_server.tar.gz", + ZoneKind::CockroachDb => "cockroachdb.tar.gz", + ZoneKind::Crucible => "crucible.tar.gz", + ZoneKind::CruciblePantry => "crucible_pantry.tar.gz", + ZoneKind::ExternalDns => "external_dns.tar.gz", + ZoneKind::InternalDns => "internal_dns.tar.gz", + ZoneKind::Nexus => "nexus.tar.gz", + ZoneKind::Oximeter => "oximeter.tar.gz", + } + } + + fn service_prefix(self) -> &'static str { + match self { + ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => NTP_PREFIX, + ZoneKind::Clickhouse => "clickhouse", + ZoneKind::ClickhouseKeeper => "clickhouse_keeper", + ZoneKind::ClickhouseServer => "clickhouse_server", + ZoneKind::CockroachDb => "cockroachdb", + ZoneKind::Crucible => "crucible", + ZoneKind::CruciblePantry => "crucible/pantry", + ZoneKind::ExternalDns => "external_dns", + ZoneKind::InternalDns => "internal_dns", + ZoneKind::Nexus => "nexus", + ZoneKind::Oximeter => "oximeter", + } + } + + fn name_prefix(self) -> &'static str { + match self { + ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => NTP_PREFIX, + ZoneKind::Clickhouse => "clickhouse", + ZoneKind::ClickhouseKeeper => "clickhouse-keeper", + ZoneKind::ClickhouseServer => "clickhouse-server", + ZoneKind::CockroachDb => "cockroach", + ZoneKind::Crucible => "crucible", + ZoneKind::CruciblePantry => "crucible-pantry", + ZoneKind::ExternalDns => "external-dns", + ZoneKind::InternalDns => "internal-dns", + ZoneKind::Nexus => "nexus", + ZoneKind::Oximeter => "oximeter", + } + } + + fn report_str(self) -> &'static str { + match self { + ZoneKind::BoundaryNtp => "boundary_ntp", + ZoneKind::Clickhouse => "clickhouse", + ZoneKind::ClickhouseKeeper => "clickhouse_keeper", + ZoneKind::ClickhouseServer => "clickhouse_server", + ZoneKind::CockroachDb => "cockroach_db", + ZoneKind::Crucible => "crucible", + ZoneKind::CruciblePantry => "crucible_pantry", + ZoneKind::ExternalDns => "external_dns", + ZoneKind::InternalDns => "internal_dns", + ZoneKind::InternalNtp => "internal_ntp", + ZoneKind::Nexus => "nexus", + ZoneKind::Oximeter => "oximeter", + } + } + + fn artifact_id_name(self) -> &'static str { + match self { + ZoneKind::BoundaryNtp => "ntp", + ZoneKind::Clickhouse => "clickhouse", + ZoneKind::ClickhouseKeeper => "clickhouse_keeper", + ZoneKind::ClickhouseServer => "clickhouse_server", + ZoneKind::CockroachDb => "cockroachdb", + ZoneKind::Crucible => "crucible-zone", + ZoneKind::CruciblePantry => "crucible-pantry-zone", + ZoneKind::ExternalDns => "external-dns", + ZoneKind::InternalDns => "internal-dns", + ZoneKind::InternalNtp => "ntp", + ZoneKind::Nexus => "nexus", + ZoneKind::Oximeter => "oximeter", + } + } + + fn is_control_plane_zone_artifact(self, artifact_id: &ArtifactId) -> bool { + artifact_id + .kind + .to_known() + .map(|kind| matches!(kind, KnownArtifactKind::Zone)) + .unwrap_or(false) + && artifact_id.name == self.artifact_id_name() + } +} + +/// Map an artifact ID name to the corresponding file name in the install +/// dataset. +/// +/// We don't allow mapping artifact ID names to `ZoneKind` because the map +/// isn't bijective -- both internal and boundary NTP zones use the same +/// `ntp` artifact. But the artifact ID name and the name in the install +/// dataset do form a bijective map. +pub fn artifact_id_name_to_install_dataset_file( + artifact_id_name: &str, +) -> Option<&'static str> { + let zone_kind = match artifact_id_name { + "ntp" => ZoneKind::BoundaryNtp, + "clickhouse" => ZoneKind::Clickhouse, + "clickhouse_keeper" => ZoneKind::ClickhouseKeeper, + "clickhouse_server" => ZoneKind::ClickhouseServer, + "cockroachdb" => ZoneKind::CockroachDb, + "crucible-zone" => ZoneKind::Crucible, + "crucible-pantry-zone" => ZoneKind::CruciblePantry, + "external-dns" => ZoneKind::ExternalDns, + "internal-dns" => ZoneKind::InternalDns, + "nexus" => ZoneKind::Nexus, + "oximeter" => ZoneKind::Oximeter, + _ => return None, + }; + Some(zone_kind.artifact_in_install_dataset()) +} + +pub trait OmicronZoneTypeExt { + /// Returns the [`ZoneKind`] corresponding to this variant. + fn kind(&self) -> ZoneKind; + + /// Does this zone require time synchronization before it is initialized?" + /// + /// This function is somewhat conservative - the set of services + /// that can be launched before timesync has completed is intentionally kept + /// small, since it would be easy to add a service that expects time to be + /// reasonably synchronized. + fn requires_timesync(&self) -> bool; + + /// Returns the underlay IP address associated with this zone. + /// + /// Assumes all zone have exactly one underlay IP address (which is + /// currently true). + fn underlay_ip(&self) -> Ipv6Addr; + + /// Identifies whether this is an NTP zone + fn is_ntp(&self) -> bool; + + /// Identifies whether this is a boundary NTP zone + fn is_boundary_ntp(&self) -> bool; + + /// Identifies whether this is a Nexus zone + fn is_nexus(&self) -> bool; + + /// Identifies whether this a Crucible (not Crucible pantry) zone + fn is_crucible(&self) -> bool; + + /// This zone's external IP + fn external_ip(&self) -> Option; + + /// The service vNIC providing external connectivity to this zone + fn service_vnic( + &self, + ) -> Option<&omicron_common::api::internal::shared::NetworkInterface>; + + /// If this kind of zone has an associated dataset, return the dataset's + /// name. Otherwise, return `None`. + fn dataset_name(&self) -> Option; +} + +impl OmicronZoneTypeExt for OmicronZoneType { + fn kind(&self) -> ZoneKind { + match self { + OmicronZoneType::BoundaryNtp { .. } => ZoneKind::BoundaryNtp, + OmicronZoneType::Clickhouse { .. } => ZoneKind::Clickhouse, + OmicronZoneType::ClickhouseKeeper { .. } => { + ZoneKind::ClickhouseKeeper + } + OmicronZoneType::ClickhouseServer { .. } => { + ZoneKind::ClickhouseServer + } + OmicronZoneType::CockroachDb { .. } => ZoneKind::CockroachDb, + OmicronZoneType::Crucible { .. } => ZoneKind::Crucible, + OmicronZoneType::CruciblePantry { .. } => ZoneKind::CruciblePantry, + OmicronZoneType::ExternalDns { .. } => ZoneKind::ExternalDns, + OmicronZoneType::InternalDns { .. } => ZoneKind::InternalDns, + OmicronZoneType::InternalNtp { .. } => ZoneKind::InternalNtp, + OmicronZoneType::Nexus { .. } => ZoneKind::Nexus, + OmicronZoneType::Oximeter { .. } => ZoneKind::Oximeter, + } + } + + fn requires_timesync(&self) -> bool { + match self { + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::InternalDns { .. } => false, + _ => true, + } + } + + fn underlay_ip(&self) -> Ipv6Addr { + match self { + OmicronZoneType::BoundaryNtp { address, .. } + | OmicronZoneType::Clickhouse { address, .. } + | OmicronZoneType::ClickhouseKeeper { address, .. } + | OmicronZoneType::ClickhouseServer { address, .. } + | OmicronZoneType::CockroachDb { address, .. } + | OmicronZoneType::Crucible { address, .. } + | OmicronZoneType::CruciblePantry { address } + | OmicronZoneType::ExternalDns { http_address: address, .. } + | OmicronZoneType::InternalNtp { address } + | OmicronZoneType::Nexus { internal_address: address, .. } + | OmicronZoneType::Oximeter { address } => *address.ip(), + OmicronZoneType::InternalDns { + http_address: address, + dns_address, + .. + } => { + debug_assert_eq!(address.ip(), dns_address.ip()); + *address.ip() + } + } + } + + fn is_ntp(&self) -> bool { + matches!( + self, + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } + ) + } + + fn is_boundary_ntp(&self) -> bool { + matches!(self, OmicronZoneType::BoundaryNtp { .. }) + } + + fn is_nexus(&self) -> bool { + matches!(self, OmicronZoneType::Nexus { .. }) + } + + fn is_crucible(&self) -> bool { + matches!(self, OmicronZoneType::Crucible { .. }) + } + + fn external_ip(&self) -> Option { + match self { + OmicronZoneType::Nexus { external_ip, .. } => Some(*external_ip), + OmicronZoneType::ExternalDns { dns_address, .. } => { + Some(dns_address.ip()) + } + OmicronZoneType::BoundaryNtp { snat_cfg, .. } => Some(snat_cfg.ip), + _ => None, + } + } + + fn service_vnic( + &self, + ) -> Option<&omicron_common::api::internal::shared::NetworkInterface> { + match self { + OmicronZoneType::Nexus { nic, .. } + | OmicronZoneType::ExternalDns { nic, .. } + | OmicronZoneType::BoundaryNtp { nic, .. } => Some(nic), + _ => None, + } + } + + fn dataset_name(&self) -> Option { + let (dataset, dataset_kind) = match self { + OmicronZoneType::BoundaryNtp { .. } + | OmicronZoneType::InternalNtp { .. } + | OmicronZoneType::Nexus { .. } + | OmicronZoneType::Oximeter { .. } + | OmicronZoneType::CruciblePantry { .. } => None, + OmicronZoneType::Clickhouse { dataset, .. } => { + Some((dataset, DatasetKind::Clickhouse)) + } + OmicronZoneType::ClickhouseKeeper { dataset, .. } => { + Some((dataset, DatasetKind::ClickhouseKeeper)) + } + OmicronZoneType::ClickhouseServer { dataset, .. } => { + Some((dataset, DatasetKind::ClickhouseServer)) + } + OmicronZoneType::CockroachDb { dataset, .. } => { + Some((dataset, DatasetKind::Cockroach)) + } + OmicronZoneType::Crucible { dataset, .. } => { + Some((dataset, DatasetKind::Crucible)) + } + OmicronZoneType::ExternalDns { dataset, .. } => { + Some((dataset, DatasetKind::ExternalDns)) + } + OmicronZoneType::InternalDns { dataset, .. } => { + Some((dataset, DatasetKind::InternalDns)) + } + }?; + Some(DatasetName::new(dataset.pool_name, dataset_kind)) + } +} + +pub trait OmicronZoneConfigExt { + /// Returns the underlay IP address associated with this zone. + /// + /// Assumes all zone have exactly one underlay IP address (which is + /// currently true). + fn underlay_ip(&self) -> Ipv6Addr; + + fn zone_name(&self) -> String; + + fn dataset_name(&self) -> Option; +} + +impl OmicronZoneConfigExt for OmicronZoneConfig { + fn underlay_ip(&self) -> Ipv6Addr { + self.zone_type.underlay_ip() + } + + fn zone_name(&self) -> String { + illumos_utils::running_zone::InstalledZone::get_zone_name( + self.zone_type.kind().zone_prefix(), + Some(self.id), + ) + } + + fn dataset_name(&self) -> Option { + self.zone_type.dataset_name() + } +} + +pub trait ConfigReconcilerInventoryExt { + /// Iterate over all running zones as reported by the last reconciliation + /// result. + /// + /// This includes zones that are both present in `last_reconciled_config` + /// and whose status in `zones` indicates "successfully running". + fn running_omicron_zones(&self) + -> impl Iterator; + + /// Iterate over all zones contained in the most-recently-reconciled sled + /// config and report their status as of that reconciliation. + fn reconciled_omicron_zones( + &self, + ) -> impl Iterator; + + /// Given a sled config, produce a reconciler result that sled-agent could + /// have emitted if reconciliation succeeded. + /// + /// This method should only be used by tests and dev tools; real code should + /// look at the actual `last_reconciliation` value from the parent + /// [`Inventory`]. + fn debug_assume_success( + config: OmicronSledConfig, + ) -> ConfigReconcilerInventory; + + /// Given a sled config, update an existing reconciler result to simulate an + /// output that sled-agent could have emitted if reconciliation succeeded. + /// + /// This method should only be used by tests and dev tools; real code should + /// look at the actual `last_reconciliation` value from the parent + /// [`Inventory`]. + fn debug_update_assume_success(&mut self, config: OmicronSledConfig); +} + +impl ConfigReconcilerInventoryExt for ConfigReconcilerInventory { + fn running_omicron_zones( + &self, + ) -> impl Iterator { + self.zones.iter().filter_map(|(zone_id, result)| match result { + ConfigReconcilerInventoryResult::Ok => { + self.last_reconciled_config.zones.get(zone_id) + } + ConfigReconcilerInventoryResult::Err { .. } => None, + }) + } + + fn reconciled_omicron_zones( + &self, + ) -> impl Iterator + { + self.zones.iter().filter_map(|(zone_id, result)| { + let config = self.last_reconciled_config.zones.get(zone_id)?; + Some((config, result)) + }) + } + + fn debug_assume_success( + config: OmicronSledConfig, + ) -> ConfigReconcilerInventory { + let mut ret = ConfigReconcilerInventory { + last_reconciled_config: OmicronSledConfig::default(), + external_disks: BTreeMap::new(), + datasets: BTreeMap::new(), + orphaned_datasets: IdOrdMap::new(), + zones: BTreeMap::new(), + remove_mupdate_override: None, + boot_partitions: ::debug_assume_success(), + }; + ret.debug_update_assume_success(config); + ret + } + + fn debug_update_assume_success(&mut self, config: OmicronSledConfig) { + let external_disks = config + .disks + .iter() + .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) + .collect(); + let datasets = config + .datasets + .iter() + .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) + .collect(); + let zones = config + .zones + .iter() + .map(|z| (z.id, ConfigReconcilerInventoryResult::Ok)) + .collect(); + let remove_mupdate_override = + config.remove_mupdate_override.map(|_| { + RemoveMupdateOverrideInventory { + boot_disk_result: Ok( + RemoveMupdateOverrideBootSuccessInventory::Removed, + ), + non_boot_message: + "mupdate override successfully removed on non-boot disks" + .to_owned(), + } + }); + + self.last_reconciled_config = config; + self.external_disks = external_disks; + self.datasets = datasets; + self.orphaned_datasets = IdOrdMap::new(); + self.zones = zones; + self.remove_mupdate_override = remove_mupdate_override; + } +} + +pub trait HostPhase2DesiredContentsExt { + /// The artifact hash described by `self`, if it has one. + fn artifact_hash(&self) -> Option; +} + +impl HostPhase2DesiredContentsExt for HostPhase2DesiredContents { + fn artifact_hash(&self) -> Option { + match self { + Self::CurrentContents => None, + Self::Artifact { hash } => Some(*hash), + } + } +} + +pub trait OmicronZoneImageSourceExt { + /// Return the artifact hash used for the zone image, if the zone's image + /// source is from the artifact store. + fn artifact_hash(&self) -> Option; +} + +impl OmicronZoneImageSourceExt for OmicronZoneImageSource { + fn artifact_hash(&self) -> Option { + if let OmicronZoneImageSource::Artifact { hash } = self { + Some(*hash) + } else { + None + } + } +} + +pub trait BootPartitionContentsExt { + fn slot_details( + &self, + slot: M2Slot, + ) -> &Result; + fn debug_assume_success() -> BootPartitionContents; +} + +impl BootPartitionContentsExt for BootPartitionContents { + fn slot_details( + &self, + slot: M2Slot, + ) -> &Result { + match slot { + M2Slot::A => &self.slot_a, + M2Slot::B => &self.slot_b, + } + } + + fn debug_assume_success() -> BootPartitionContents { + BootPartitionContents { + boot_disk: Ok(M2Slot::A), + slot_a: Ok(BootPartitionDetails { + header: BootImageHeader { + flags: 0, + data_size: 1000, + image_size: 1000, + target_size: 1000, + sha256: [0; 32], + image_name: "fake from debug_assume_success()".to_string(), + }, + artifact_hash: ArtifactHash([0x0a; 32]), + artifact_size: 1000, + }), + slot_b: Ok(BootPartitionDetails { + header: BootImageHeader { + flags: 0, + data_size: 1000, + image_size: 1000, + target_size: 1000, + sha256: [1; 32], + image_name: "fake from debug_assume_success()".to_string(), + }, + artifact_hash: ArtifactHash([0x0b; 32]), + artifact_size: 1000, + }), + } + } +} + +// Display helper types + +pub struct ZoneImageResolverInventoryDisplay<'a> { + inner: &'a ZoneImageResolverInventory, +} + +impl fmt::Display for ZoneImageResolverInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ZoneImageResolverInventory { zone_manifest, mupdate_override } = + self.inner; + writeln!(f, "zone manifest:")?; + let mut indented = IndentWriter::new(" ", f); + write!(indented, "{}", zone_manifest.display())?; + let f = indented.into_inner(); + writeln!(f, "mupdate override:")?; + let mut indented = IndentWriter::new(" ", f); + write!(indented, "{}", mupdate_override.display())?; + Ok(()) + } +} + +pub struct ZoneManifestInventoryDisplay<'a> { + inner: &'a ZoneManifestInventory, +} + +impl fmt::Display for ZoneManifestInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut f = f; + let ZoneManifestInventory { + boot_disk_path, + boot_inventory, + non_boot_status, + } = self.inner; + writeln!(f, "path on boot disk: {}", boot_disk_path)?; + match boot_inventory { + Ok(boot_inventory) => { + writeln!(f, "boot disk inventory:")?; + let mut indented = IndentWriter::new(" ", f); + write!(indented, "{}", boot_inventory.display())?; + f = indented.into_inner(); + } + Err(error) => { + writeln!( + f, + "error obtaining zone manifest on boot disk: {error}" + )?; + } + } + if non_boot_status.is_empty() { + writeln!(f, "no non-boot disks")?; + } else { + writeln!(f, "non-boot disk status:")?; + for non_boot in non_boot_status { + let mut indented = IndentWriter::new_skip_initial(" ", f); + writeln!(indented, " - {}", non_boot.display())?; + f = indented.into_inner(); + } + } + Ok(()) + } +} + +pub struct ZoneManifestBootInventoryDisplay<'a> { + inner: &'a ZoneManifestBootInventory, +} + +impl fmt::Display for ZoneManifestBootInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut f = f; + let ZoneManifestBootInventory { source, artifacts } = self.inner; + writeln!(f, "manifest generated by {}", source)?; + if artifacts.is_empty() { + writeln!( + f, + "no artifacts in install dataset (this should only be seen in simulated systems)" + )?; + } else { + writeln!(f, "artifacts in install dataset:")?; + for artifact in artifacts { + let mut indented = IndentWriter::new_skip_initial(" ", f); + writeln!(indented, " - {}", artifact.display())?; + f = indented.into_inner(); + } + } + Ok(()) + } +} + +pub struct ZoneArtifactInventoryDisplay<'a> { + inner: &'a ZoneArtifactInventory, +} + +impl fmt::Display for ZoneArtifactInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ZoneArtifactInventory { + file_name, + path: _, + expected_size, + expected_hash, + status, + } = self.inner; + write!( + f, + "{file_name} (expected {expected_size} bytes with hash {expected_hash}): " + )?; + match status { + Ok(()) => write!(f, "ok"), + Err(message) => write!(f, "error: {message}"), + } + } +} + +pub struct ZoneManifestNonBootInventoryDisplay<'a> { + inner: &'a ZoneManifestNonBootInventory, +} + +impl fmt::Display for ZoneManifestNonBootInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let ZoneManifestNonBootInventory { + zpool_id: _, + path, + is_valid, + message, + } = self.inner; + write!( + f, + "{path} ({}): {message}", + if *is_valid { "valid" } else { "invalid" } + ) + } +} + +pub struct MupdateOverrideInventoryDisplay<'a> { + inner: &'a MupdateOverrideInventory, +} + +impl fmt::Display for MupdateOverrideInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut f = f; + let MupdateOverrideInventory { + boot_disk_path, + boot_override, + non_boot_status, + } = self.inner; + writeln!(f, "path on boot disk: {boot_disk_path}")?; + match boot_override { + Ok(Some(boot_override)) => { + writeln!( + f, + "override on boot disk: {}", + boot_override.display() + )?; + } + Ok(None) => { + writeln!(f, "no override on boot disk")?; + } + Err(error) => { + writeln!(f, "error obtaining override on boot disk: {error}")?; + } + } + if non_boot_status.is_empty() { + writeln!(f, "no non-boot disks")?; + } else { + writeln!(f, "non-boot disk status:")?; + for non_boot in non_boot_status { + let mut indented = IndentWriter::new_skip_initial(" ", f); + writeln!(indented, " - {}", non_boot.display())?; + f = indented.into_inner(); + } + } + Ok(()) + } +} + +pub struct MupdateOverrideBootInventoryDisplay<'a> { + inner: &'a MupdateOverrideBootInventory, +} + +impl fmt::Display for MupdateOverrideBootInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let MupdateOverrideBootInventory { mupdate_override_id } = self.inner; + write!(f, "{}", mupdate_override_id) + } +} + +pub struct MupdateOverrideNonBootInventoryDisplay<'a> { + inner: &'a MupdateOverrideNonBootInventory, +} + +impl fmt::Display for MupdateOverrideNonBootInventoryDisplay<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let MupdateOverrideNonBootInventory { + zpool_id: _, + path, + is_valid, + message, + } = self.inner; + write!( + f, + "{path} ({}): {message}", + if *is_valid { "valid" } else { "invalid" } + ) + } +} + +pub trait ZoneImageResolverInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> ZoneImageResolverInventoryDisplay<'_>; + + /// Returns a new, fake inventory for tests. + fn new_fake() -> ZoneImageResolverInventory; +} + +impl ZoneImageResolverInventoryExt for ZoneImageResolverInventory { + fn display(&self) -> ZoneImageResolverInventoryDisplay<'_> { + ZoneImageResolverInventoryDisplay { inner: self } + } + + fn new_fake() -> ZoneImageResolverInventory { + ZoneImageResolverInventory { + zone_manifest: ::new_fake(), + mupdate_override: ::new_fake(), + } + } +} + +pub trait ZoneManifestInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> ZoneManifestInventoryDisplay<'_>; + + /// Returns a new, empty inventory for tests. + fn new_fake() -> ZoneManifestInventory; +} + +impl ZoneManifestInventoryExt for ZoneManifestInventory { + fn display(&self) -> ZoneManifestInventoryDisplay<'_> { + ZoneManifestInventoryDisplay { inner: self } + } + + fn new_fake() -> ZoneManifestInventory { + ZoneManifestInventory { + boot_disk_path: Utf8PathBuf::from("/fake/path/install/zones.json"), + boot_inventory: Ok(::new_fake()), + non_boot_status: IdOrdMap::new(), + } + } +} + +pub trait ZoneManifestBootInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> ZoneManifestBootInventoryDisplay<'_>; + + /// Returns a new, empty inventory for tests. + /// + /// For a more representative selection of real zones, see `representative` + /// in `nexus-inventory`. + fn new_fake() -> ZoneManifestBootInventory; +} + +impl ZoneManifestBootInventoryExt for ZoneManifestBootInventory { + fn display(&self) -> ZoneManifestBootInventoryDisplay<'_> { + ZoneManifestBootInventoryDisplay { inner: self } + } + + fn new_fake() -> ZoneManifestBootInventory { + ZoneManifestBootInventory { + source: OmicronZoneManifestSource::Installinator { + mupdate_id: MupdateUuid::nil(), + }, + artifacts: IdOrdMap::new(), + } + } +} + +pub trait ZoneArtifactInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> ZoneArtifactInventoryDisplay<'_>; +} + +impl ZoneArtifactInventoryExt for ZoneArtifactInventory { + fn display(&self) -> ZoneArtifactInventoryDisplay<'_> { + ZoneArtifactInventoryDisplay { inner: self } + } +} + +pub trait ZoneManifestNonBootInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> ZoneManifestNonBootInventoryDisplay<'_>; +} + +impl ZoneManifestNonBootInventoryExt for ZoneManifestNonBootInventory { + fn display(&self) -> ZoneManifestNonBootInventoryDisplay<'_> { + ZoneManifestNonBootInventoryDisplay { inner: self } + } +} + +pub trait MupdateOverrideInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> MupdateOverrideInventoryDisplay<'_>; + + /// Returns a new, empty inventory for tests. + fn new_fake() -> MupdateOverrideInventory; +} + +impl MupdateOverrideInventoryExt for MupdateOverrideInventory { + fn display(&self) -> MupdateOverrideInventoryDisplay<'_> { + MupdateOverrideInventoryDisplay { inner: self } + } + + fn new_fake() -> MupdateOverrideInventory { + MupdateOverrideInventory { + boot_disk_path: Utf8PathBuf::from( + "/fake/path/install/mupdate_override.json", + ), + boot_override: Ok(None), + non_boot_status: IdOrdMap::new(), + } + } +} + +pub trait MupdateOverrideBootInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> MupdateOverrideBootInventoryDisplay<'_>; +} + +impl MupdateOverrideBootInventoryExt for MupdateOverrideBootInventory { + fn display(&self) -> MupdateOverrideBootInventoryDisplay<'_> { + MupdateOverrideBootInventoryDisplay { inner: self } + } +} + +pub trait MupdateOverrideNonBootInventoryExt { + /// Returns a displayer for this inventory. + fn display(&self) -> MupdateOverrideNonBootInventoryDisplay<'_>; +} + +impl MupdateOverrideNonBootInventoryExt for MupdateOverrideNonBootInventory { + fn display(&self) -> MupdateOverrideNonBootInventoryDisplay<'_> { + MupdateOverrideNonBootInventoryDisplay { inner: self } + } +} diff --git a/sled-agent/types/src/sled.rs b/sled-agent/types/src/sled.rs index 0dd099e1a4b..a8ff2605ba9 100644 --- a/sled-agent/types/src/sled.rs +++ b/sled-agent/types/src/sled.rs @@ -4,6 +4,41 @@ //! Types related to operating on sleds. +use std::net::{Ipv6Addr, SocketAddrV6}; + +use omicron_common::address; +use sha3::{Digest, Sha3_256}; + pub use sled_agent_types_versions::latest::sled::*; pub const SWITCH_ZONE_BASEBOARD_FILE: &str = "/opt/oxide/baseboard.json"; + +/// Extension trait for [`StartSledAgentRequest`]. +pub trait StartSledAgentRequestExt { + fn sled_address(&self) -> SocketAddrV6; + fn switch_zone_ip(&self) -> Ipv6Addr; + + /// Compute the sha3_256 digest of `self.rack_id` to use as a `salt` + /// for disk encryption. We don't want to include other values that are + /// consistent across sleds as it would prevent us from moving drives + /// between sleds. + fn hash_rack_id(&self) -> [u8; 32]; +} + +impl StartSledAgentRequestExt for StartSledAgentRequest { + fn sled_address(&self) -> SocketAddrV6 { + address::get_sled_address(self.body.subnet) + } + + fn switch_zone_ip(&self) -> Ipv6Addr { + address::get_switch_zone_address(self.body.subnet) + } + + fn hash_rack_id(&self) -> [u8; 32] { + // We know the unwrap succeeds as a Sha3_256 digest is 32 bytes + Sha3_256::digest(self.body.rack_id.as_bytes()) + .as_slice() + .try_into() + .unwrap() + } +} diff --git a/sled-agent/types/src/zone_bundle.rs b/sled-agent/types/src/zone_bundle.rs index d89e562ab95..ec25bf327e2 100644 --- a/sled-agent/types/src/zone_bundle.rs +++ b/sled-agent/types/src/zone_bundle.rs @@ -10,6 +10,42 @@ use camino::Utf8PathBuf; pub use sled_agent_types_versions::latest::zone_bundle::*; +// Note: ZoneBundleMetadata::new(), PriorityOrder::new(), CleanupPeriod::as_duration(), +// StorageLimit::as_u8(), StorageLimit::bytes_available() remain as inherent methods +// in the versions crate because they access private fields. To move them here, +// the versions crate would need to expose those fields or provide getters. + +pub trait PriorityOrderExt { + fn compare_metadata( + &self, + lhs: &ZoneBundleMetadata, + rhs: &ZoneBundleMetadata, + ) -> Ordering; +} + +impl PriorityOrderExt for PriorityOrder { + fn compare_metadata( + &self, + lhs: &ZoneBundleMetadata, + rhs: &ZoneBundleMetadata, + ) -> Ordering { + // PriorityOrder implements Deref to the array, so self.iter() works + for dim in self.iter() { + let ord = match dim { + PriorityDimension::Cause => lhs.cause.cmp(&rhs.cause), + PriorityDimension::Time => { + lhs.time_created.cmp(&rhs.time_created) + } + }; + if matches!(ord, Ordering::Equal) { + continue; + } + return ord; + } + Ordering::Equal + } +} + /// Information about a zone bundle. /// /// This type is not published in the API, so it remains defined here diff --git a/sled-agent/types/src/zone_images.rs b/sled-agent/types/src/zone_images.rs index 642be56e47a..b95f97ab755 100644 --- a/sled-agent/types/src/zone_images.rs +++ b/sled-agent/types/src/zone_images.rs @@ -22,6 +22,8 @@ use sled_agent_types_versions::latest::inventory::ZoneArtifactInventory; use sled_agent_types_versions::latest::inventory::ZoneImageResolverInventory; use sled_agent_types_versions::latest::inventory::ZoneKind; use sled_agent_types_versions::latest::inventory::ZoneManifestBootInventory; + +use crate::inventory::ZoneKindExt; use sled_agent_types_versions::latest::inventory::ZoneManifestInventory; use sled_agent_types_versions::latest::inventory::ZoneManifestNonBootInventory; use slog::{error, info, o, warn}; diff --git a/sled-agent/types/versions/Cargo.toml b/sled-agent/types/versions/Cargo.toml index a70565a47c0..6e9bec4d76c 100644 --- a/sled-agent/types/versions/Cargo.toml +++ b/sled-agent/types/versions/Cargo.toml @@ -13,7 +13,6 @@ chrono.workspace = true daft.workspace = true iddqd.workspace = true illumos-utils.workspace = true -indent_write.workspace = true async-trait.workspace = true bootstore.workspace = true omicron-common.workspace = true diff --git a/sled-agent/types/versions/src/add_dual_stack_external_ip_config/inventory.rs b/sled-agent/types/versions/src/add_dual_stack_external_ip_config/inventory.rs index b44725452a1..e05b5a91fc9 100644 --- a/sled-agent/types/versions/src/add_dual_stack_external_ip_config/inventory.rs +++ b/sled-agent/types/versions/src/add_dual_stack_external_ip_config/inventory.rs @@ -10,7 +10,6 @@ use chrono::{DateTime, Utc}; use iddqd::IdOrdItem; use iddqd::IdOrdMap; use iddqd::id_upcast; -use omicron_common::disk::{DatasetKind, DatasetName}; use omicron_common::ledger::Ledgerable; use omicron_common::{ api::{ @@ -30,8 +29,7 @@ use crate::v1::inventory::{ BootPartitionContents, ConfigReconcilerInventoryResult, HostPhase2DesiredSlots, InventoryDataset, InventoryDisk, InventoryZpool, OmicronZoneDataset, OmicronZoneImageSource, OrphanedDataset, - RemoveMupdateOverrideBootSuccessInventory, RemoveMupdateOverrideInventory, - SledRole, ZoneImageResolverInventory, ZoneKind, + RemoveMupdateOverrideInventory, SledRole, ZoneImageResolverInventory, }; use crate::v10; use sled_hardware_types::{Baseboard, SledCpuFamily}; @@ -74,107 +72,6 @@ pub struct ConfigReconcilerInventory { pub remove_mupdate_override: Option, } -impl ConfigReconcilerInventory { - /// Iterate over all running zones as reported by the last reconciliation - /// result. - /// - /// This includes zones that are both present in `last_reconciled_config` - /// and whose status in `zones` indicates "successfully running". - pub fn running_omicron_zones( - &self, - ) -> impl Iterator { - self.zones.iter().filter_map(|(zone_id, result)| match result { - ConfigReconcilerInventoryResult::Ok => { - self.last_reconciled_config.zones.get(zone_id) - } - ConfigReconcilerInventoryResult::Err { .. } => None, - }) - } - - /// Iterate over all zones contained in the most-recently-reconciled sled - /// config and report their status as of that reconciliation. - pub fn reconciled_omicron_zones( - &self, - ) -> impl Iterator - { - // `self.zones` may contain zone IDs that aren't present in - // `last_reconciled_config` at all, if we failed to _shut down_ zones - // that are no longer present in the config. We use `filter_map` to - // strip those out, and only report on the configured zones. - self.zones.iter().filter_map(|(zone_id, result)| { - let config = self.last_reconciled_config.zones.get(zone_id)?; - Some((config, result)) - }) - } - - /// Given a sled config, produce a reconciler result that sled-agent could - /// have emitted if reconciliation succeeded. - /// - /// This method should only be used by tests and dev tools; real code should - /// look at the actual `last_reconciliation` value from the parent - /// [`Inventory`]. - pub fn debug_assume_success(config: OmicronSledConfig) -> Self { - let mut ret = Self { - // These fields will be filled in by `debug_update_assume_success`. - last_reconciled_config: OmicronSledConfig::default(), - external_disks: BTreeMap::new(), - datasets: BTreeMap::new(), - orphaned_datasets: IdOrdMap::new(), - zones: BTreeMap::new(), - remove_mupdate_override: None, - - // These fields will not. - boot_partitions: BootPartitionContents::debug_assume_success(), - }; - - ret.debug_update_assume_success(config); - - ret - } - - /// Given a sled config, update an existing reconciler result to simulate an - /// output that sled-agent could have emitted if reconciliation succeeded. - /// - /// This method should only be used by tests and dev tools; real code should - /// look at the actual `last_reconciliation` value from the parent - /// [`Inventory`]. - pub fn debug_update_assume_success(&mut self, config: OmicronSledConfig) { - let external_disks = config - .disks - .iter() - .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let datasets = config - .datasets - .iter() - .map(|d| (d.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let zones = config - .zones - .iter() - .map(|z| (z.id, ConfigReconcilerInventoryResult::Ok)) - .collect(); - let remove_mupdate_override = - config.remove_mupdate_override.map(|_| { - RemoveMupdateOverrideInventory { - boot_disk_result: Ok( - RemoveMupdateOverrideBootSuccessInventory::Removed, - ), - non_boot_message: "mupdate override successfully removed \ - on non-boot disks" - .to_owned(), - } - }); - - self.last_reconciled_config = config; - self.external_disks = external_disks; - self.datasets = datasets; - self.orphaned_datasets = IdOrdMap::new(); - self.zones = zones; - self.remove_mupdate_override = remove_mupdate_override; - } -} - /// Status of the sled-agent-config-reconciler task. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] #[serde(tag = "status", rename_all = "snake_case")] @@ -261,11 +158,6 @@ pub struct OmicronZonesConfig { pub zones: Vec, } -impl OmicronZonesConfig { - /// Generation 1 of `OmicronZonesConfig` is always the set of no zones. - pub const INITIAL_GENERATION: Generation = Generation::from_u32(1); -} - /// Describes one Omicron-managed zone running on a sled #[derive( Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, @@ -295,27 +187,6 @@ impl IdOrdItem for OmicronZoneConfig { id_upcast!(); } -impl OmicronZoneConfig { - /// Returns the underlay IP address associated with this zone. - /// - /// Assumes all zone have exactly one underlay IP address (which is - /// currently true). - pub fn underlay_ip(&self) -> Ipv6Addr { - self.zone_type.underlay_ip() - } - - pub fn zone_name(&self) -> String { - illumos_utils::running_zone::InstalledZone::get_zone_name( - self.zone_type.kind().zone_prefix(), - Some(self.id), - ) - } - - pub fn dataset_name(&self) -> Option { - self.zone_type.dataset_name() - } -} - /// Describes what kind of zone this is (i.e., what component is running in it) /// as well as any type-specific configuration #[derive( @@ -415,219 +286,6 @@ pub enum OmicronZoneType { }, } -impl OmicronZoneType { - /// Returns the [`ZoneKind`] corresponding to this variant. - pub fn kind(&self) -> ZoneKind { - match self { - OmicronZoneType::BoundaryNtp { .. } => ZoneKind::BoundaryNtp, - OmicronZoneType::Clickhouse { .. } => ZoneKind::Clickhouse, - OmicronZoneType::ClickhouseKeeper { .. } => { - ZoneKind::ClickhouseKeeper - } - OmicronZoneType::ClickhouseServer { .. } => { - ZoneKind::ClickhouseServer - } - OmicronZoneType::CockroachDb { .. } => ZoneKind::CockroachDb, - OmicronZoneType::Crucible { .. } => ZoneKind::Crucible, - OmicronZoneType::CruciblePantry { .. } => ZoneKind::CruciblePantry, - OmicronZoneType::ExternalDns { .. } => ZoneKind::ExternalDns, - OmicronZoneType::InternalDns { .. } => ZoneKind::InternalDns, - OmicronZoneType::InternalNtp { .. } => ZoneKind::InternalNtp, - OmicronZoneType::Nexus { .. } => ZoneKind::Nexus, - OmicronZoneType::Oximeter { .. } => ZoneKind::Oximeter, - } - } - - /// Does this zone require time synchronization before it is initialized?" - /// - /// This function is somewhat conservative - the set of services - /// that can be launched before timesync has completed is intentionally kept - /// small, since it would be easy to add a service that expects time to be - /// reasonably synchronized. - pub fn requires_timesync(&self) -> bool { - match self { - // These zones can be initialized and started before time has been - // synchronized. For the NTP zones, this should be self-evident -- - // we need the NTP zone to actually perform time synchronization! - // - // The DNS zone is a bit of an exception here, since the NTP zone - // itself may rely on DNS lookups as a dependency. - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::InternalDns { .. } => false, - _ => true, - } - } - - /// Returns the underlay IP address associated with this zone. - /// - /// Assumes all zone have exactly one underlay IP address (which is - /// currently true). - pub fn underlay_ip(&self) -> Ipv6Addr { - match self { - OmicronZoneType::BoundaryNtp { address, .. } - | OmicronZoneType::Clickhouse { address, .. } - | OmicronZoneType::ClickhouseKeeper { address, .. } - | OmicronZoneType::ClickhouseServer { address, .. } - | OmicronZoneType::CockroachDb { address, .. } - | OmicronZoneType::Crucible { address, .. } - | OmicronZoneType::CruciblePantry { address } - | OmicronZoneType::ExternalDns { http_address: address, .. } - | OmicronZoneType::InternalNtp { address } - | OmicronZoneType::Nexus { internal_address: address, .. } - | OmicronZoneType::Oximeter { address } => *address.ip(), - OmicronZoneType::InternalDns { - http_address: address, - dns_address, - .. - } => { - // InternalDns is the only variant that carries two - // `SocketAddrV6`s that are both on the underlay network. We - // expect these to have the same IP address. - debug_assert_eq!(address.ip(), dns_address.ip()); - *address.ip() - } - } - } - - /// Identifies whether this is an NTP zone - pub fn is_ntp(&self) -> bool { - match self { - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } => true, - - OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::ExternalDns { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Nexus { .. } - | OmicronZoneType::Oximeter { .. } => false, - } - } - - /// Identifies whether this is a boundary NTP zone - pub fn is_boundary_ntp(&self) -> bool { - matches!(self, OmicronZoneType::BoundaryNtp { .. }) - } - - /// Identifies whether this is a Nexus zone - pub fn is_nexus(&self) -> bool { - match self { - OmicronZoneType::Nexus { .. } => true, - - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::ExternalDns { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Oximeter { .. } => false, - } - } - - /// Identifies whether this a Crucible (not Crucible pantry) zone - pub fn is_crucible(&self) -> bool { - match self { - OmicronZoneType::Crucible { .. } => true, - - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::ExternalDns { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Nexus { .. } - | OmicronZoneType::Oximeter { .. } => false, - } - } - - /// This zone's external IP - pub fn external_ip(&self) -> Option { - match self { - OmicronZoneType::Nexus { external_ip, .. } => Some(*external_ip), - OmicronZoneType::ExternalDns { dns_address, .. } => { - Some(dns_address.ip()) - } - OmicronZoneType::BoundaryNtp { snat_cfg, .. } => Some(snat_cfg.ip), - - OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Oximeter { .. } => None, - } - } - - /// The service vNIC providing external connectivity to this zone - pub fn service_vnic(&self) -> Option<&NetworkInterface> { - match self { - OmicronZoneType::Nexus { nic, .. } - | OmicronZoneType::ExternalDns { nic, .. } - | OmicronZoneType::BoundaryNtp { nic, .. } => Some(nic), - - OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Clickhouse { .. } - | OmicronZoneType::ClickhouseKeeper { .. } - | OmicronZoneType::ClickhouseServer { .. } - | OmicronZoneType::CockroachDb { .. } - | OmicronZoneType::Crucible { .. } - | OmicronZoneType::CruciblePantry { .. } - | OmicronZoneType::InternalDns { .. } - | OmicronZoneType::Oximeter { .. } => None, - } - } - - /// If this kind of zone has an associated dataset, return the dataset's - /// name. Otherwise, return `None`. - pub fn dataset_name(&self) -> Option { - let (dataset, dataset_kind) = match self { - OmicronZoneType::BoundaryNtp { .. } - | OmicronZoneType::InternalNtp { .. } - | OmicronZoneType::Nexus { .. } - | OmicronZoneType::Oximeter { .. } - | OmicronZoneType::CruciblePantry { .. } => None, - OmicronZoneType::Clickhouse { dataset, .. } => { - Some((dataset, DatasetKind::Clickhouse)) - } - OmicronZoneType::ClickhouseKeeper { dataset, .. } => { - Some((dataset, DatasetKind::ClickhouseKeeper)) - } - OmicronZoneType::ClickhouseServer { dataset, .. } => { - Some((dataset, DatasetKind::ClickhouseServer)) - } - OmicronZoneType::CockroachDb { dataset, .. } => { - Some((dataset, DatasetKind::Cockroach)) - } - OmicronZoneType::Crucible { dataset, .. } => { - Some((dataset, DatasetKind::Crucible)) - } - OmicronZoneType::ExternalDns { dataset, .. } => { - Some((dataset, DatasetKind::ExternalDns)) - } - OmicronZoneType::InternalDns { dataset, .. } => { - Some((dataset, DatasetKind::InternalDns)) - } - }?; - - Some(DatasetName::new(dataset.pool_name, dataset_kind)) - } -} - fn default_nexus_lockstep_port() -> u16 { omicron_common::address::NEXUS_LOCKSTEP_PORT } diff --git a/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs b/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs index e986bcb130e..99c906d3968 100644 --- a/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs +++ b/sled-agent/types/versions/src/add_dual_stack_shared_network_interfaces/inventory.rs @@ -160,11 +160,6 @@ pub struct OmicronZonesConfig { pub zones: Vec, } -impl OmicronZonesConfig { - /// Generation 1 of `OmicronZonesConfig` is always the set of no zones. - pub const INITIAL_GENERATION: Generation = Generation::from_u32(1); -} - /// Describes one Omicron-managed zone running on a sled #[derive( Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq, Hash, diff --git a/sled-agent/types/versions/src/initial/disk.rs b/sled-agent/types/versions/src/initial/disk.rs index 5ba09e00f65..9d774590dbc 100644 --- a/sled-agent/types/versions/src/initial/disk.rs +++ b/sled-agent/types/versions/src/initial/disk.rs @@ -59,16 +59,3 @@ pub enum DiskStateRequested { Destroyed, Faulted, } - -impl DiskStateRequested { - /// Returns whether the requested state is attached to an Instance or not. - pub fn is_attached(&self) -> bool { - match self { - DiskStateRequested::Detached => false, - DiskStateRequested::Destroyed => false, - DiskStateRequested::Faulted => false, - - DiskStateRequested::Attached(_) => true, - } - } -} diff --git a/sled-agent/types/versions/src/initial/instance.rs b/sled-agent/types/versions/src/initial/instance.rs index 3c05b49134f..51dec9bb930 100644 --- a/sled-agent/types/versions/src/initial/instance.rs +++ b/sled-agent/types/versions/src/initial/instance.rs @@ -14,13 +14,7 @@ use omicron_common::api::internal::shared::DhcpConfig; use omicron_common::api::internal::shared::external_ip::v1::SourceNatConfig; use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; use omicron_uuid_kinds::{InstanceUuid, PropolisUuid}; -use propolis_api_types::instance_spec::{ - SpecKey, - components::backends::{ - CrucibleStorageBackend, FileStorageBackend, VirtioNetworkBackend, - }, - v0::{ComponentV0, InstanceSpecV0}, -}; +use propolis_api_types::instance_spec::v0::InstanceSpecV0; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -113,56 +107,6 @@ pub struct InstanceMetadata { #[derive(Clone, Debug, Serialize, Deserialize, JsonSchema)] pub struct VmmSpec(pub InstanceSpecV0); -/// Extension trait for VmmSpec to provide helper methods. -pub trait VmmSpecExt { - fn crucible_backends( - &self, - ) -> impl Iterator; - - fn viona_backends( - &self, - ) -> impl Iterator; - - fn file_backends( - &self, - ) -> impl Iterator; -} - -impl VmmSpecExt for VmmSpec { - fn crucible_backends( - &self, - ) -> impl Iterator { - self.0.components.iter().filter_map( - |(key, component)| match component { - ComponentV0::CrucibleStorageBackend(be) => Some((key, be)), - _ => None, - }, - ) - } - - fn viona_backends( - &self, - ) -> impl Iterator { - self.0.components.iter().filter_map( - |(key, component)| match component { - ComponentV0::VirtioNetworkBackend(be) => Some((key, be)), - _ => None, - }, - ) - } - - fn file_backends( - &self, - ) -> impl Iterator { - self.0.components.iter().filter_map( - |(key, component)| match component { - ComponentV0::FileStorageBackend(be) => Some((key, be)), - _ => None, - }, - ) - } -} - /// VPC firewall rule after object name resolution has been performed by Nexus #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, JsonSchema)] pub struct ResolvedVpcFirewallRule { @@ -228,16 +172,6 @@ impl VmmStateRequested { VmmStateRequested::Reboot => "reboot", } } - - /// Returns true if the state represents a stopped Instance. - pub fn is_stopped(&self) -> bool { - match self { - VmmStateRequested::MigrationTarget(_) => false, - VmmStateRequested::Running => false, - VmmStateRequested::Stopped => true, - VmmStateRequested::Reboot => false, - } - } } /// The response sent from a request to unregister an instance. diff --git a/sled-agent/types/versions/src/initial/inventory.rs b/sled-agent/types/versions/src/initial/inventory.rs index 282425e59e9..452020ecbd0 100644 --- a/sled-agent/types/versions/src/initial/inventory.rs +++ b/sled-agent/types/versions/src/initial/inventory.rs @@ -5,7 +5,6 @@ //! Inventory types for Sled Agent API versions 1-3. use std::collections::BTreeMap; -use std::fmt::{self, Write}; use std::net::{IpAddr, Ipv6Addr, SocketAddr, SocketAddrV6}; use std::time::Duration; @@ -15,7 +14,6 @@ use daft::Diffable; use iddqd::IdOrdItem; use iddqd::IdOrdMap; use iddqd::id_upcast; -use indent_write::fmt::IndentWriter; use omicron_common::api::external::{ByteCount, Generation}; use omicron_common::api::internal::shared::external_ip::v1::SourceNatConfig; use omicron_common::api::internal::shared::network_interface::v1::NetworkInterface; @@ -24,16 +22,15 @@ use omicron_common::disk::{ }; use omicron_common::snake_case_result; use omicron_common::snake_case_result::SnakeCaseResult; -use omicron_common::update::{ArtifactId, OmicronZoneManifestSource}; +use omicron_common::update::OmicronZoneManifestSource; use omicron_common::zpool_name::ZpoolName; use omicron_uuid_kinds::{ - DatasetUuid, InternalZpoolUuid, MupdateOverrideUuid, MupdateUuid, - OmicronZoneUuid, PhysicalDiskUuid, SledUuid, ZpoolUuid, + DatasetUuid, InternalZpoolUuid, MupdateOverrideUuid, OmicronZoneUuid, + PhysicalDiskUuid, SledUuid, ZpoolUuid, }; use schemars::schema::{Schema, SchemaObject}; use schemars::{JsonSchema, r#gen::SchemaGenerator}; use serde::{Deserialize, Serialize}; -use tufaceous_artifact::KnownArtifactKind; // Export these types for convenience -- this way, dependents don't have to // depend on sled-hardware-types. pub use sled_hardware_types::{Baseboard, SledCpuFamily}; @@ -143,16 +140,6 @@ pub enum HostPhase2DesiredContents { Artifact { hash: ArtifactHash }, } -impl HostPhase2DesiredContents { - /// The artifact hash described by `self`, if it has one. - pub fn artifact_hash(&self) -> Option { - match self { - Self::CurrentContents => None, - Self::Artifact { hash } => Some(*hash), - } - } -} - /// Describes the desired contents for both host phase 2 slots. #[derive(Clone, Debug, Deserialize, Serialize, JsonSchema, PartialEq, Eq)] #[serde(rename_all = "snake_case")] @@ -208,48 +195,6 @@ pub struct BootPartitionContents { pub slot_b: Result, } -impl BootPartitionContents { - pub fn slot_details( - &self, - slot: M2Slot, - ) -> &Result { - match slot { - M2Slot::A => &self.slot_a, - M2Slot::B => &self.slot_b, - } - } - - pub fn debug_assume_success() -> Self { - Self { - boot_disk: Ok(M2Slot::A), - slot_a: Ok(BootPartitionDetails { - header: BootImageHeader { - flags: 0, - data_size: 1000, - image_size: 1000, - target_size: 1000, - sha256: [0; 32], - image_name: "fake from debug_assume_success()".to_string(), - }, - artifact_hash: ArtifactHash([0x0a; 32]), - artifact_size: 1000, - }), - slot_b: Ok(BootPartitionDetails { - header: BootImageHeader { - flags: 0, - data_size: 1000, - image_size: 1000, - target_size: 1000, - sha256: [1; 32], - image_name: "fake from debug_assume_success()".to_string(), - }, - artifact_hash: ArtifactHash([0x0b; 32]), - artifact_size: 1000, - }), - } - } -} - #[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] pub struct BootPartitionDetails { pub header: BootImageHeader, @@ -347,48 +292,6 @@ pub struct ZoneImageResolverInventory { pub mupdate_override: MupdateOverrideInventory, } -impl ZoneImageResolverInventory { - /// Returns a new, fake inventory for tests. - pub fn new_fake() -> Self { - Self { - zone_manifest: ZoneManifestInventory::new_fake(), - mupdate_override: MupdateOverrideInventory::new_fake(), - } - } - - /// Returns a displayer for this inventory. - pub fn display(&self) -> ZoneImageResolverInventoryDisplay<'_> { - ZoneImageResolverInventoryDisplay { inner: self } - } -} - -/// Displayer for a [`ZoneImageResolverInventory`] -pub struct ZoneImageResolverInventoryDisplay<'a> { - inner: &'a ZoneImageResolverInventory, -} - -impl fmt::Display for ZoneImageResolverInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let ZoneImageResolverInventory { zone_manifest, mupdate_override } = - self.inner; - - writeln!(f, "zone manifest:")?; - let mut indented = IndentWriter::new(" ", f); - // Use write! rather than writeln! because zone_manifest.display() - // always produces a newline at the end. - write!(indented, "{}", zone_manifest.display())?; - let f = indented.into_inner(); - - writeln!(f, "mupdate override:")?; - let mut indented = IndentWriter::new(" ", f); - // Use write! rather than writeln! because mupdate_override.display() - // always produces a newline at the end. - write!(indented, "{}", mupdate_override.display())?; - - Ok(()) - } -} - /// Inventory representation of a zone manifest. /// /// Part of [`ZoneImageResolverInventory`]. @@ -413,71 +316,6 @@ pub struct ZoneManifestInventory { pub non_boot_status: IdOrdMap, } -impl ZoneManifestInventory { - /// Returns a new, empty inventory for tests. - pub fn new_fake() -> Self { - Self { - boot_disk_path: Utf8PathBuf::from("/fake/path/install/zones.json"), - boot_inventory: Ok(ZoneManifestBootInventory::new_fake()), - non_boot_status: IdOrdMap::new(), - } - } - - /// Returns a displayer for this inventory. - pub fn display(&self) -> ZoneManifestInventoryDisplay<'_> { - ZoneManifestInventoryDisplay { inner: self } - } -} - -/// Displayer for a [`ZoneManifestInventory`] -#[derive(Clone, Debug)] -pub struct ZoneManifestInventoryDisplay<'a> { - inner: &'a ZoneManifestInventory, -} - -impl fmt::Display for ZoneManifestInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut f = f; - - let ZoneManifestInventory { - boot_disk_path, - boot_inventory, - non_boot_status, - } = self.inner; - writeln!(f, "path on boot disk: {}", boot_disk_path)?; - - match boot_inventory { - Ok(boot_inventory) => { - writeln!(f, "boot disk inventory:")?; - let mut indented = IndentWriter::new(" ", f); - // Use write! rather than writeln! because - // boot_inventory.display() always ends with a newline. - write!(indented, "{}", boot_inventory.display())?; - f = indented.into_inner(); - } - Err(error) => { - writeln!( - f, - "error obtaining zone manifest on boot disk: {error}" - )?; - } - } - - if non_boot_status.is_empty() { - writeln!(f, "no non-boot disks")?; - } else { - writeln!(f, "non-boot disk status:")?; - for non_boot in non_boot_status { - let mut indented = IndentWriter::new_skip_initial(" ", f); - writeln!(indented, " - {}", non_boot.display())?; - f = indented.into_inner(); - } - } - - Ok(()) - } -} - /// Inventory representation of zone artifacts on the boot disk. /// /// Part of [`ZoneManifestInventory`]. @@ -495,58 +333,6 @@ pub struct ZoneManifestBootInventory { pub artifacts: IdOrdMap, } -impl ZoneManifestBootInventory { - /// Returns a new, empty inventory for tests. - /// - /// For a more representative selection of real zones, see `representative` - /// in `nexus-inventory`. - pub fn new_fake() -> Self { - Self { - source: OmicronZoneManifestSource::Installinator { - mupdate_id: MupdateUuid::nil(), - }, - artifacts: IdOrdMap::new(), - } - } - - /// Returns a displayer for this inventory. - pub fn display(&self) -> ZoneManifestBootInventoryDisplay<'_> { - ZoneManifestBootInventoryDisplay { inner: self } - } -} - -/// Displayer for a [`ZoneManifestBootInventory`]. -#[derive(Clone, Debug)] -pub struct ZoneManifestBootInventoryDisplay<'a> { - inner: &'a ZoneManifestBootInventory, -} - -impl fmt::Display for ZoneManifestBootInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut f = f; - - let ZoneManifestBootInventory { source, artifacts } = self.inner; - writeln!(f, "manifest generated by {}", source)?; - if artifacts.is_empty() { - writeln!( - f, - "no artifacts in install dataset \ - (this should only be seen in simulated systems)" - )?; - } else { - writeln!(f, "artifacts in install dataset:")?; - - for artifact in artifacts { - let mut indented = IndentWriter::new_skip_initial(" ", f); - writeln!(indented, " - {}", artifact.display())?; - f = indented.into_inner(); - } - } - - Ok(()) - } -} - /// Inventory representation of a single zone artifact on a boot disk. /// /// Part of [`ZoneManifestBootInventory`]. @@ -575,13 +361,6 @@ pub struct ZoneArtifactInventory { pub status: Result<(), String>, } -impl ZoneArtifactInventory { - /// Returns a displayer for this inventory. - pub fn display(&self) -> ZoneArtifactInventoryDisplay<'_> { - ZoneArtifactInventoryDisplay { inner: self } - } -} - impl IdOrdItem for ZoneArtifactInventory { type Key<'a> = &'a str; fn key(&self) -> Self::Key<'_> { @@ -591,36 +370,6 @@ impl IdOrdItem for ZoneArtifactInventory { id_upcast!(); } -/// Displayer for [`ZoneArtifactInventory`]. -#[derive(Clone, Debug)] -pub struct ZoneArtifactInventoryDisplay<'a> { - inner: &'a ZoneArtifactInventory, -} - -impl fmt::Display for ZoneArtifactInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let ZoneArtifactInventory { - file_name, - // We don't show the path here because surrounding code typically - // displays the path. We could make this controllable in the future - // via a method on `ZoneArtifactInventoryDisplay`. - path: _, - expected_size, - expected_hash, - status, - } = self.inner; - write!( - f, - "{file_name} (expected {expected_size} bytes \ - with hash {expected_hash}): ", - )?; - match status { - Ok(()) => write!(f, "ok"), - Err(message) => write!(f, "error: {message}"), - } - } -} - /// Inventory representation of a zone manifest on a non-boot disk. /// /// Unlike [`ZoneManifestBootInventory`] which is structured since @@ -650,13 +399,6 @@ pub struct ZoneManifestNonBootInventory { pub message: String, } -impl ZoneManifestNonBootInventory { - /// Returns a displayer for this inventory. - pub fn display(&self) -> ZoneManifestNonBootInventoryDisplay<'_> { - ZoneManifestNonBootInventoryDisplay { inner: self } - } -} - impl IdOrdItem for ZoneManifestNonBootInventory { type Key<'a> = InternalZpoolUuid; fn key(&self) -> Self::Key<'_> { @@ -665,29 +407,6 @@ impl IdOrdItem for ZoneManifestNonBootInventory { id_upcast!(); } -/// Displayer for a [`ZoneManifestNonBootInventory`]. -#[derive(Clone, Debug)] -pub struct ZoneManifestNonBootInventoryDisplay<'a> { - inner: &'a ZoneManifestNonBootInventory, -} - -impl fmt::Display for ZoneManifestNonBootInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let ZoneManifestNonBootInventory { - // The zpool ID is part of the path, so displaying it is redundant. - zpool_id: _, - path, - is_valid, - message, - } = self.inner; - write!( - f, - "{path} ({}): {message}", - if *is_valid { "valid" } else { "invalid" }, - ) - } -} - /// Inventory representation of MUPdate override status. /// /// Part of [`ZoneImageResolverInventory`]. @@ -713,72 +432,6 @@ pub struct MupdateOverrideInventory { pub non_boot_status: IdOrdMap, } -impl MupdateOverrideInventory { - /// Returns a new, empty inventory for tests. - pub fn new_fake() -> Self { - Self { - boot_disk_path: Utf8PathBuf::from( - "/fake/path/install/mupdate_override.json", - ), - boot_override: Ok(None), - non_boot_status: IdOrdMap::new(), - } - } - - /// Returns a displayer for this inventory. - pub fn display(&self) -> MupdateOverrideInventoryDisplay<'_> { - MupdateOverrideInventoryDisplay { inner: self } - } -} - -/// A displayer for [`MupdateOverrideInventory`]. -#[derive(Clone, Debug)] -pub struct MupdateOverrideInventoryDisplay<'a> { - inner: &'a MupdateOverrideInventory, -} - -impl fmt::Display for MupdateOverrideInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut f = f; - - let MupdateOverrideInventory { - boot_disk_path, - boot_override, - non_boot_status, - } = self.inner; - - writeln!(f, "path on boot disk: {boot_disk_path}")?; - match boot_override { - Ok(Some(boot_override)) => { - writeln!( - f, - "override on boot disk: {}", - boot_override.display() - )?; - } - Ok(None) => { - writeln!(f, "no override on boot disk")?; - } - Err(error) => { - writeln!(f, "error obtaining override on boot disk: {error}")?; - } - } - - if non_boot_status.is_empty() { - writeln!(f, "no non-boot disks")?; - } else { - writeln!(f, "non-boot disk status:")?; - for non_boot in non_boot_status { - let mut indented = IndentWriter::new_skip_initial(" ", f); - writeln!(indented, " - {}", non_boot.display())?; - f = indented.into_inner(); - } - } - - Ok(()) - } -} - /// Inventory representation of the MUPdate override on the boot disk. #[derive(Clone, Debug, PartialEq, Eq, Deserialize, JsonSchema, Serialize)] pub struct MupdateOverrideBootInventory { @@ -790,25 +443,6 @@ pub struct MupdateOverrideBootInventory { pub mupdate_override_id: MupdateOverrideUuid, } -impl MupdateOverrideBootInventory { - /// Returns a displayer for this inventory. - pub fn display(&self) -> MupdateOverrideBootInventoryDisplay<'_> { - MupdateOverrideBootInventoryDisplay { inner: self } - } -} - -#[derive(Clone, Debug)] -pub struct MupdateOverrideBootInventoryDisplay<'a> { - inner: &'a MupdateOverrideBootInventory, -} - -impl fmt::Display for MupdateOverrideBootInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let MupdateOverrideBootInventory { mupdate_override_id } = self.inner; - write!(f, "{}", mupdate_override_id) - } -} - /// Inventory representation of the MUPdate override on a non-boot disk. /// /// Unlike [`MupdateOverrideBootInventory`] which is structured since @@ -839,13 +473,6 @@ pub struct MupdateOverrideNonBootInventory { pub message: String, } -impl MupdateOverrideNonBootInventory { - /// Returns a displayer for this inventory. - pub fn display(&self) -> MupdateOverrideNonBootInventoryDisplay<'_> { - MupdateOverrideNonBootInventoryDisplay { inner: self } - } -} - impl IdOrdItem for MupdateOverrideNonBootInventory { type Key<'a> = InternalZpoolUuid; fn key(&self) -> Self::Key<'_> { @@ -854,29 +481,6 @@ impl IdOrdItem for MupdateOverrideNonBootInventory { id_upcast!(); } -/// Displayer for a [`MupdateOverrideNonBootInventory`]. -#[derive(Clone, Debug)] -pub struct MupdateOverrideNonBootInventoryDisplay<'a> { - inner: &'a MupdateOverrideNonBootInventory, -} - -impl fmt::Display for MupdateOverrideNonBootInventoryDisplay<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let MupdateOverrideNonBootInventory { - // The zpool ID is part of the path, so displaying it is redundant. - zpool_id: _, - path, - is_valid, - message, - } = self.inner; - write!( - f, - "{path} ({}): {message}", - if *is_valid { "valid" } else { "invalid" }, - ) - } -} - /// Where Sled Agent should get the image for a zone. #[derive( Clone, @@ -913,16 +517,6 @@ pub enum OmicronZoneImageSource { } impl OmicronZoneImageSource { - /// Return the artifact hash used for the zone image, if the zone's image - /// source is from the artifact store. - pub fn artifact_hash(&self) -> Option { - if let OmicronZoneImageSource::Artifact { hash } = self { - Some(*hash) - } else { - None - } - } - // See `OmicronZoneConfig`. This is a separate function instead of being // `impl Default` because we don't want to accidentally use this default // outside of `serde(default)`. @@ -992,187 +586,6 @@ pub enum ZoneKind { Oximeter, } -impl ZoneKind { - /// The NTP prefix used for both BoundaryNtp and InternalNtp zones and - /// services. - pub const NTP_PREFIX: &'static str = "ntp"; - - /// Return a string that is used to construct **zone names**. This string - /// is guaranteed to be stable over time. - pub fn zone_prefix(self) -> &'static str { - match self { - // BoundaryNtp and InternalNtp both use "ntp". - ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => Self::NTP_PREFIX, - ZoneKind::Clickhouse => "clickhouse", - ZoneKind::ClickhouseKeeper => "clickhouse_keeper", - ZoneKind::ClickhouseServer => "clickhouse_server", - // Note "cockroachdb" for historical reasons. - ZoneKind::CockroachDb => "cockroachdb", - ZoneKind::Crucible => "crucible", - ZoneKind::CruciblePantry => "crucible_pantry", - ZoneKind::ExternalDns => "external_dns", - ZoneKind::InternalDns => "internal_dns", - ZoneKind::Nexus => "nexus", - ZoneKind::Oximeter => "oximeter", - } - } - - /// Return a string that identifies **zone image filenames** in the install - /// dataset. - /// - /// This method is exactly equivalent to `format!("{}.tar.gz", - /// self.zone_prefix())`, but returns `&'static str`s. A unit test ensures - /// they stay consistent. - pub fn artifact_in_install_dataset(self) -> &'static str { - match self { - // BoundaryNtp and InternalNtp both use "ntp". - ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => "ntp.tar.gz", - ZoneKind::Clickhouse => "clickhouse.tar.gz", - ZoneKind::ClickhouseKeeper => "clickhouse_keeper.tar.gz", - ZoneKind::ClickhouseServer => "clickhouse_server.tar.gz", - // Note "cockroachdb" for historical reasons. - ZoneKind::CockroachDb => "cockroachdb.tar.gz", - ZoneKind::Crucible => "crucible.tar.gz", - ZoneKind::CruciblePantry => "crucible_pantry.tar.gz", - ZoneKind::ExternalDns => "external_dns.tar.gz", - ZoneKind::InternalDns => "internal_dns.tar.gz", - ZoneKind::Nexus => "nexus.tar.gz", - ZoneKind::Oximeter => "oximeter.tar.gz", - } - } - - /// Return a string that is used to construct **SMF service names**. This - /// string is guaranteed to be stable over time. - pub fn service_prefix(self) -> &'static str { - match self { - // BoundaryNtp and InternalNtp both use "ntp". - ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => Self::NTP_PREFIX, - ZoneKind::Clickhouse => "clickhouse", - ZoneKind::ClickhouseKeeper => "clickhouse_keeper", - ZoneKind::ClickhouseServer => "clickhouse_server", - // Note "cockroachdb" for historical reasons. - ZoneKind::CockroachDb => "cockroachdb", - ZoneKind::Crucible => "crucible", - // Note "crucible/pantry" for historical reasons. - ZoneKind::CruciblePantry => "crucible/pantry", - ZoneKind::ExternalDns => "external_dns", - ZoneKind::InternalDns => "internal_dns", - ZoneKind::Nexus => "nexus", - ZoneKind::Oximeter => "oximeter", - } - } - - /// Return a string suitable for use **in `Name` instances**. This string - /// is guaranteed to be stable over time. - /// - /// This string uses dashes rather than underscores, as required by `Name`. - pub fn name_prefix(self) -> &'static str { - match self { - // BoundaryNtp and InternalNtp both use "ntp" here. - ZoneKind::BoundaryNtp | ZoneKind::InternalNtp => Self::NTP_PREFIX, - ZoneKind::Clickhouse => "clickhouse", - ZoneKind::ClickhouseKeeper => "clickhouse-keeper", - ZoneKind::ClickhouseServer => "clickhouse-server", - // Note "cockroach" for historical reasons. - ZoneKind::CockroachDb => "cockroach", - ZoneKind::Crucible => "crucible", - ZoneKind::CruciblePantry => "crucible-pantry", - ZoneKind::ExternalDns => "external-dns", - ZoneKind::InternalDns => "internal-dns", - ZoneKind::Nexus => "nexus", - ZoneKind::Oximeter => "oximeter", - } - } - - /// Return a string that is used for reporting and error messages. This is - /// **not guaranteed** to be stable. - /// - /// If you're displaying a user-friendly message, prefer this method. - pub fn report_str(self) -> &'static str { - match self { - ZoneKind::BoundaryNtp => "boundary_ntp", - ZoneKind::Clickhouse => "clickhouse", - ZoneKind::ClickhouseKeeper => "clickhouse_keeper", - ZoneKind::ClickhouseServer => "clickhouse_server", - ZoneKind::CockroachDb => "cockroach_db", - ZoneKind::Crucible => "crucible", - ZoneKind::CruciblePantry => "crucible_pantry", - ZoneKind::ExternalDns => "external_dns", - ZoneKind::InternalDns => "internal_dns", - ZoneKind::InternalNtp => "internal_ntp", - ZoneKind::Nexus => "nexus", - ZoneKind::Oximeter => "oximeter", - } - } - - /// Return a string used as an artifact name for control-plane zones. - /// This is **not guaranteed** to be stable. - /// - /// These strings match the `ArtifactId::name`s Nexus constructs when - /// unpacking the composite control-plane artifact in a TUF repo. Currently, - /// these are chosen by reading the `pkg` value of the `oxide.json` object - /// inside each zone image tarball. - pub fn artifact_id_name(self) -> &'static str { - match self { - ZoneKind::BoundaryNtp => "ntp", - ZoneKind::Clickhouse => "clickhouse", - ZoneKind::ClickhouseKeeper => "clickhouse_keeper", - ZoneKind::ClickhouseServer => "clickhouse_server", - ZoneKind::CockroachDb => "cockroachdb", - ZoneKind::Crucible => "crucible-zone", - ZoneKind::CruciblePantry => "crucible-pantry-zone", - ZoneKind::ExternalDns => "external-dns", - ZoneKind::InternalDns => "internal-dns", - ZoneKind::InternalNtp => "ntp", - ZoneKind::Nexus => "nexus", - ZoneKind::Oximeter => "oximeter", - } - } - - /// Map an artifact ID name to the corresponding file name in the install - /// dataset. - /// - /// We don't allow mapping artifact ID names to `ZoneKind` because the map - /// isn't bijective -- both internal and boundary NTP zones use the same - /// `ntp` artifact. But the artifact ID name and the name in the install - /// dataset do form a bijective map. - pub fn artifact_id_name_to_install_dataset_file( - artifact_id_name: &str, - ) -> Option<&'static str> { - let zone_kind = match artifact_id_name { - // We arbitrarily select BoundaryNtp to perform the mapping with. - "ntp" => ZoneKind::BoundaryNtp, - "clickhouse" => ZoneKind::Clickhouse, - "clickhouse_keeper" => ZoneKind::ClickhouseKeeper, - "clickhouse_server" => ZoneKind::ClickhouseServer, - "cockroachdb" => ZoneKind::CockroachDb, - "crucible-zone" => ZoneKind::Crucible, - "crucible-pantry-zone" => ZoneKind::CruciblePantry, - "external-dns" => ZoneKind::ExternalDns, - "internal-dns" => ZoneKind::InternalDns, - "nexus" => ZoneKind::Nexus, - "oximeter" => ZoneKind::Oximeter, - _ => return None, - }; - - Some(zone_kind.artifact_in_install_dataset()) - } - - /// Return true if an artifact represents a control plane zone image - /// of this kind. - pub fn is_control_plane_zone_artifact( - self, - artifact_id: &ArtifactId, - ) -> bool { - artifact_id - .kind - .to_known() - .map(|kind| matches!(kind, KnownArtifactKind::Zone)) - .unwrap_or(false) - && artifact_id.name == self.artifact_id_name() - } -} - // Used for schemars to be able to be used with camino: // See https://github.com/camino-rs/camino/issues/91#issuecomment-2027908513 fn path_schema(generator: &mut SchemaGenerator) -> Schema { diff --git a/sled-agent/types/versions/src/initial/sled.rs b/sled-agent/types/versions/src/initial/sled.rs index a678b90816b..8d2fda2e707 100644 --- a/sled-agent/types/versions/src/initial/sled.rs +++ b/sled-agent/types/versions/src/initial/sled.rs @@ -4,16 +4,13 @@ //! Sled-related types for the Sled Agent API. -use std::net::{Ipv6Addr, SocketAddrV6}; - use async_trait::async_trait; use daft::Diffable; -use omicron_common::address::{self, Ipv6Subnet, SLED_PREFIX}; +use omicron_common::address::{Ipv6Subnet, SLED_PREFIX}; use omicron_common::ledger::Ledgerable; use omicron_uuid_kinds::SledUuid; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; -use sha3::{Digest, Sha3_256}; use uuid::Uuid; /// A representation of a Baseboard ID as used in the inventory subsystem @@ -71,28 +68,6 @@ pub struct StartSledAgentRequest { pub body: StartSledAgentRequestBody, } -impl StartSledAgentRequest { - pub fn sled_address(&self) -> SocketAddrV6 { - address::get_sled_address(self.body.subnet) - } - - pub fn switch_zone_ip(&self) -> Ipv6Addr { - address::get_switch_zone_address(self.body.subnet) - } - - /// Compute the sha3_256 digest of `self.rack_id` to use as a `salt` - /// for disk encryption. We don't want to include other values that are - /// consistent across sleds as it would prevent us from moving drives - /// between sleds. - pub fn hash_rack_id(&self) -> [u8; 32] { - // We know the unwrap succeeds as a Sha3_256 digest is 32 bytes - Sha3_256::digest(self.body.rack_id.as_bytes()) - .as_slice() - .try_into() - .unwrap() - } -} - /// This is the actual app level data of `StartSledAgentRequest` /// /// We nest it below the "header" of `generation` and `schema_version` so that diff --git a/sled-agent/types/versions/src/latest.rs b/sled-agent/types/versions/src/latest.rs index 23b67460b22..596b66779ea 100644 --- a/sled-agent/types/versions/src/latest.rs +++ b/sled-agent/types/versions/src/latest.rs @@ -64,7 +64,6 @@ pub mod instance { pub use crate::v1::instance::VmmPutStateBody; pub use crate::v1::instance::VmmPutStateResponse; pub use crate::v1::instance::VmmSpec; - pub use crate::v1::instance::VmmSpecExt; pub use crate::v1::instance::VmmStateRequested; pub use crate::v1::instance::VmmUnregisterResponse; pub use crate::v1::instance::VpcPathParam; diff --git a/sled-agent/zone-images-examples/src/lib.rs b/sled-agent/zone-images-examples/src/lib.rs index 2eeb67cc3ee..594c8018668 100644 --- a/sled-agent/zone-images-examples/src/lib.rs +++ b/sled-agent/zone-images-examples/src/lib.rs @@ -21,7 +21,7 @@ use omicron_common::update::{ }; use omicron_uuid_kinds::{InternalZpoolUuid, MupdateOverrideUuid, MupdateUuid}; use sha2::{Digest, Sha256}; -use sled_agent_types::inventory::ZoneKind; +use sled_agent_types::inventory::{ZoneKind, ZoneKindExt}; use sled_agent_types::zone_images::{ ArcIoError, ArcSerdeJsonError, ArtifactReadResult, InstallMetadataReadError, ZoneManifestArtifactResult, diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs index 6f84cb406be..58a3550dd2e 100644 --- a/sled-agent/zone-images/src/source_resolver.rs +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -124,7 +124,9 @@ mod tests { use sled_agent_config_reconciler::{ HostPhase2PreparedContents, ResolverStatusExt, }; - use sled_agent_types::inventory::{HostPhase2DesiredContents, ZoneKind}; + use sled_agent_types::inventory::{ + HostPhase2DesiredContents, ZoneKind, ZoneKindExt, + }; use sled_agent_types::zone_images::{ MupdateOverrideReadError, OmicronZoneFileSource, OmicronZoneImageLocation, RAMDISK_IMAGE_PATH, ZoneImageLocationError, From 70391eef447222f1f19fd32230adbae170c32fcc Mon Sep 17 00:00:00 2001 From: Rain Date: Sun, 14 Dec 2025 03:49:49 +0000 Subject: [PATCH 2/6] fix doc comment Created using spr 1.3.6-beta.1 --- sled-agent/types/src/inventory.rs | 25 ++++++++++++++++++ .../types/versions/src/initial/inventory.rs | 26 ------------------- 2 files changed, 25 insertions(+), 26 deletions(-) diff --git a/sled-agent/types/src/inventory.rs b/sled-agent/types/src/inventory.rs index 497be890077..14f1ac50620 100644 --- a/sled-agent/types/src/inventory.rs +++ b/sled-agent/types/src/inventory.rs @@ -25,6 +25,31 @@ pub const ZONES_CONFIG_INITIAL_GENERATION: Generation = Generation::from_u32(1); /// The NTP prefix used for both BoundaryNtp and InternalNtp zones and services. pub const NTP_PREFIX: &str = "ntp"; +/// String representations and other utilities on [`ZoneKind`]. +/// +/// There are no fewer than six string representations for this type, all +/// slightly different from each other. +/// +/// 1. [`Self::zone_prefix`]: Used to construct zone names. +/// 2. [`Self::service_prefix`]: Used to construct SMF service names. +/// 3. [`Self::name_prefix`]: Used to construct `Name` instances. +/// 4. [`Self::report_str`]: Used for reporting and testing. +/// 5. [`Self::artifact_id_name`]: Used to match TUF artifact IDs. +/// 6. [`Self::artifact_in_install_dataset`]: Used to match zone image tarballs +/// in the install dataset. (This method is equivalent to appending `.tar.gz` +/// to the result of [`Self::zone_prefix`].) +/// +/// There is no `Display` impl to ensure that users explicitly choose the +/// representation they want. (Please play close attention to this! The +/// functions are all similar but different, and we don't currently have great +/// type safety around the choice.) +/// +/// ## Adding new representations +/// +/// If you have a new use case for a string representation, please reuse one of +/// the six representations if at all possible. If you must add a new one, +/// please add it here rather than doing something ad-hoc in the calling code +/// so it's more legible. pub trait ZoneKindExt { /// Return a string that is used to construct **zone names**. This string /// is guaranteed to be stable over time. diff --git a/sled-agent/types/versions/src/initial/inventory.rs b/sled-agent/types/versions/src/initial/inventory.rs index 452020ecbd0..2c1750876cd 100644 --- a/sled-agent/types/versions/src/initial/inventory.rs +++ b/sled-agent/types/versions/src/initial/inventory.rs @@ -528,32 +528,6 @@ impl OmicronZoneImageSource { /// Like [`OmicronZoneType`], but without any associated data. /// /// This enum is meant to correspond exactly 1:1 with `OmicronZoneType`. -/// -/// # String representations of this type -/// -/// There are no fewer than six string representations for this type, all -/// slightly different from each other. -/// -/// 1. [`Self::zone_prefix`]: Used to construct zone names. -/// 2. [`Self::service_prefix`]: Used to construct SMF service names. -/// 3. [`Self::name_prefix`]: Used to construct `Name` instances. -/// 4. [`Self::report_str`]: Used for reporting and testing. -/// 5. [`Self::artifact_id_name`]: Used to match TUF artifact IDs. -/// 6. [`Self::artifact_in_install_dataset`]: Used to match zone image tarballs -/// in the install dataset. (This method is equivalent to appending `.tar.gz` -/// to the result of [`Self::zone_prefix`].) -/// -/// There is no `Display` impl to ensure that users explicitly choose the -/// representation they want. (Please play close attention to this! The -/// functions are all similar but different, and we don't currently have great -/// type safety around the choice.) -/// -/// ## Adding new representations -/// -/// If you have a new use case for a string representation, please reuse one of -/// the six representations if at all possible. If you must add a new one, -/// please add it here rather than doing something ad-hoc in the calling code -/// so it's more legible. #[derive( Debug, Clone, From cb5f75215ebb881a74af457a6882350be8495faa Mon Sep 17 00:00:00 2001 From: Rain Date: Sun, 14 Dec 2025 03:53:30 +0000 Subject: [PATCH 3/6] fix a weird crate:: Created using spr 1.3.6-beta.1 --- sled-agent/types/src/zone_images.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sled-agent/types/src/zone_images.rs b/sled-agent/types/src/zone_images.rs index b95f97ab755..0d8d6650279 100644 --- a/sled-agent/types/src/zone_images.rs +++ b/sled-agent/types/src/zone_images.rs @@ -22,8 +22,6 @@ use sled_agent_types_versions::latest::inventory::ZoneArtifactInventory; use sled_agent_types_versions::latest::inventory::ZoneImageResolverInventory; use sled_agent_types_versions::latest::inventory::ZoneKind; use sled_agent_types_versions::latest::inventory::ZoneManifestBootInventory; - -use crate::inventory::ZoneKindExt; use sled_agent_types_versions::latest::inventory::ZoneManifestInventory; use sled_agent_types_versions::latest::inventory::ZoneManifestNonBootInventory; use slog::{error, info, o, warn}; @@ -32,6 +30,8 @@ use swrite::{SWrite, swriteln}; use thiserror::Error; use tufaceous_artifact::ArtifactHash; +use crate::inventory::ZoneKindExt; + /// The location to look for images shipped with the RAM disk. pub const RAMDISK_IMAGE_PATH: &str = "/opt/oxide"; From 92dbfdab78e750abd4b5625cd432a2f180cdfa40 Mon Sep 17 00:00:00 2001 From: Rain Date: Sun, 14 Dec 2025 04:00:11 +0000 Subject: [PATCH 4/6] more updates Created using spr 1.3.6-beta.1 --- sled-agent/types/src/zone_bundle.rs | 5 ---- .../types/versions/src/initial/zone_bundle.rs | 29 ++----------------- 2 files changed, 3 insertions(+), 31 deletions(-) diff --git a/sled-agent/types/src/zone_bundle.rs b/sled-agent/types/src/zone_bundle.rs index ec25bf327e2..35e1fe2d708 100644 --- a/sled-agent/types/src/zone_bundle.rs +++ b/sled-agent/types/src/zone_bundle.rs @@ -10,11 +10,6 @@ use camino::Utf8PathBuf; pub use sled_agent_types_versions::latest::zone_bundle::*; -// Note: ZoneBundleMetadata::new(), PriorityOrder::new(), CleanupPeriod::as_duration(), -// StorageLimit::as_u8(), StorageLimit::bytes_available() remain as inherent methods -// in the versions crate because they access private fields. To move them here, -// the versions crate would need to expose those fields or provide getters. - pub trait PriorityOrderExt { fn compare_metadata( &self, diff --git a/sled-agent/types/versions/src/initial/zone_bundle.rs b/sled-agent/types/versions/src/initial/zone_bundle.rs index dd48453502b..e4abd702300 100644 --- a/sled-agent/types/versions/src/initial/zone_bundle.rs +++ b/sled-agent/types/versions/src/initial/zone_bundle.rs @@ -4,7 +4,6 @@ //! Zone bundle types for Sled Agent API version 1. -use std::cmp::Ordering; use std::collections::HashSet; use std::time::Duration; @@ -163,6 +162,9 @@ pub enum PriorityDimension { /// are pruned first, to maintain the dataset quota. Note that bundles are /// sorted by each dimension in the order in which they appear, with each /// dimension having higher priority than the next. +/// +/// TODO: The serde deserializer does not currently verify uniqueness of +/// dimensions. #[derive(Clone, Copy, Debug, Deserialize, JsonSchema, PartialEq, Serialize)] pub struct PriorityOrder([PriorityDimension; PriorityOrder::EXPECTED_SIZE]); @@ -240,31 +242,6 @@ impl PriorityOrder { pub fn as_slice(&self) -> &[PriorityDimension] { &self.0 } - - /// Order zone bundle metadata according to the contained priority. - /// - /// We sort the metadata by each dimension, in the order in which it - /// appears. That means earlier dimensions have higher priority than later - /// ones. - pub fn compare_metadata( - &self, - lhs: &ZoneBundleMetadata, - rhs: &ZoneBundleMetadata, - ) -> Ordering { - for dim in self.0.iter() { - let ord = match dim { - PriorityDimension::Cause => lhs.cause.cmp(&rhs.cause), - PriorityDimension::Time => { - lhs.time_created.cmp(&rhs.time_created) - } - }; - if matches!(ord, Ordering::Equal) { - continue; - } - return ord; - } - Ordering::Equal - } } /// A period on which bundles are automatically cleaned up. From c1ae25db8b9602b2b81aad1caae807ccafa091ed Mon Sep 17 00:00:00 2001 From: Rain Date: Sun, 14 Dec 2025 23:16:02 +0000 Subject: [PATCH 5/6] regenerate openapi doc Created using spr 1.3.6-beta.1 --- openapi/nexus-lockstep.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openapi/nexus-lockstep.json b/openapi/nexus-lockstep.json index 2f9724cdb93..6b7a5709747 100644 --- a/openapi/nexus-lockstep.json +++ b/openapi/nexus-lockstep.json @@ -9110,7 +9110,7 @@ ] }, "ZoneKind": { - "description": "Like [`OmicronZoneType`], but without any associated data.\n\nThis enum is meant to correspond exactly 1:1 with `OmicronZoneType`.\n\n# String representations of this type\n\nThere are no fewer than six string representations for this type, all slightly different from each other.\n\n1. [`Self::zone_prefix`]: Used to construct zone names. 2. [`Self::service_prefix`]: Used to construct SMF service names. 3. [`Self::name_prefix`]: Used to construct `Name` instances. 4. [`Self::report_str`]: Used for reporting and testing. 5. [`Self::artifact_id_name`]: Used to match TUF artifact IDs. 6. [`Self::artifact_in_install_dataset`]: Used to match zone image tarballs in the install dataset. (This method is equivalent to appending `.tar.gz` to the result of [`Self::zone_prefix`].)\n\nThere is no `Display` impl to ensure that users explicitly choose the representation they want. (Please play close attention to this! The functions are all similar but different, and we don't currently have great type safety around the choice.)\n\n## Adding new representations\n\nIf you have a new use case for a string representation, please reuse one of the six representations if at all possible. If you must add a new one, please add it here rather than doing something ad-hoc in the calling code so it's more legible.", + "description": "Like [`OmicronZoneType`], but without any associated data.\n\nThis enum is meant to correspond exactly 1:1 with `OmicronZoneType`.", "type": "string", "enum": [ "boundary_ntp", From 06393e5f85f618fd3af9d731b73ab09a21106d56 Mon Sep 17 00:00:00 2001 From: Rain Date: Mon, 15 Dec 2025 07:06:08 +0000 Subject: [PATCH 6/6] remove an unused dep Created using spr 1.3.6-beta.1 --- sled-agent/types/versions/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/sled-agent/types/versions/Cargo.toml b/sled-agent/types/versions/Cargo.toml index 6e9bec4d76c..83b541696bd 100644 --- a/sled-agent/types/versions/Cargo.toml +++ b/sled-agent/types/versions/Cargo.toml @@ -26,7 +26,6 @@ proptest = { workspace = true, optional = true } schemars.workspace = true serde.workspace = true serde_json.workspace = true -sha3.workspace = true sled-hardware-types.workspace = true strum.workspace = true test-strategy = { workspace = true, optional = true }