From 7ce10750b13d34c74a2d50df5233a4285bdca07c Mon Sep 17 00:00:00 2001 From: Rain Date: Thu, 1 May 2025 22:30:18 -0700 Subject: [PATCH 1/7] [spr] changes to main this commit is based on Created using spr 1.3.6-beta.1 [skip ci] --- Cargo.lock | 14 ++ Cargo.toml | 3 + .../src/{update.rs => update/artifact_id.rs} | 0 common/src/update/mod.rs | 9 ++ common/src/update/mupdate_override.rs | 29 ++++ installinator-common/src/progress.rs | 3 + installinator/Cargo.toml | 2 + installinator/src/write.rs | 60 +++++++- sled-agent/Cargo.toml | 1 + sled-agent/src/services.rs | 66 ++------- sled-agent/zone-images/Cargo.toml | 15 ++ sled-agent/zone-images/src/lib.rs | 12 ++ sled-agent/zone-images/src/source_resolver.rs | 138 ++++++++++++++++++ uuid-kinds/src/lib.rs | 1 + wicketd/tests/integration_tests/updates.rs | 26 ++++ 15 files changed, 323 insertions(+), 56 deletions(-) rename common/src/{update.rs => update/artifact_id.rs} (100%) create mode 100644 common/src/update/mod.rs create mode 100644 common/src/update/mupdate_override.rs create mode 100644 sled-agent/zone-images/Cargo.toml create mode 100644 sled-agent/zone-images/src/lib.rs create mode 100644 sled-agent/zone-images/src/source_resolver.rs diff --git a/Cargo.lock b/Cargo.lock index 8f0c10bdb5c..34d6dfe9635 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4740,10 +4740,12 @@ dependencies = [ "omicron-common", "omicron-ddm-admin-client", "omicron-test-utils", + "omicron-uuid-kinds", "omicron-workspace-hack", "partial-io", "proptest", "reqwest", + "serde_json", "sha2", "sled-hardware", "sled-hardware-types", @@ -7717,6 +7719,7 @@ dependencies = [ "sled-agent-client", "sled-agent-config-reconciler", "sled-agent-types", + "sled-agent-zone-images", "sled-diagnostics", "sled-hardware", "sled-hardware-types", @@ -11484,6 +11487,17 @@ dependencies = [ "uuid", ] +[[package]] +name = "sled-agent-zone-images" +version = "0.1.0" +dependencies = [ + "anyhow", + "camino", + "nexus-sled-agent-shared", + "omicron-workspace-hack", + "sled-storage", +] + [[package]] name = "sled-diagnostics" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index 34f639c3a29..77756d5524e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -127,6 +127,7 @@ members = [ "sled-agent/config-reconciler", "sled-agent/repo-depot-api", "sled-agent/types", + "sled-agent/zone-images", "sled-diagnostics", "sled-hardware", "sled-hardware/types", @@ -279,6 +280,7 @@ default-members = [ "sled-agent/config-reconciler", "sled-agent/repo-depot-api", "sled-agent/types", + "sled-agent/zone-images", "sled-diagnostics", "sled-hardware", "sled-hardware/types", @@ -666,6 +668,7 @@ sled-agent-api = { path = "sled-agent/api" } sled-agent-client = { path = "clients/sled-agent-client" } sled-agent-config-reconciler = { path = "sled-agent/config-reconciler" } sled-agent-types = { path = "sled-agent/types" } +sled-agent-zone-images = { path = "sled-agent/zone-images" } sled-diagnostics = { path = "sled-diagnostics" } sled-hardware = { path = "sled-hardware" } sled-hardware-types = { path = "sled-hardware/types" } diff --git a/common/src/update.rs b/common/src/update/artifact_id.rs similarity index 100% rename from common/src/update.rs rename to common/src/update/artifact_id.rs diff --git a/common/src/update/mod.rs b/common/src/update/mod.rs new file mode 100644 index 00000000000..12f91feb987 --- /dev/null +++ b/common/src/update/mod.rs @@ -0,0 +1,9 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +mod artifact_id; +mod mupdate_override; + +pub use artifact_id::*; +pub use mupdate_override::*; diff --git a/common/src/update/mupdate_override.rs b/common/src/update/mupdate_override.rs new file mode 100644 index 00000000000..2cdf8cecbbe --- /dev/null +++ b/common/src/update/mupdate_override.rs @@ -0,0 +1,29 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Type definitions for the MUPdate override (RFD 556). + +use std::collections::BTreeSet; + +use omicron_uuid_kinds::MupdateOverrideUuid; +use serde::{Deserialize, Serialize}; +use tufaceous_artifact::ArtifactHashId; + +/// MUPdate override information, typically serialized as JSON (RFD 556). +/// +/// When a MUPdate occurs, a file containing this information is created on the +/// install dataset of the system. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct MupdateOverrideInfo { + /// A UUID that identifies a MUPdate that occurred. + pub mupdate_uuid: MupdateOverrideUuid, + + /// Artifact hashes written out to the install dataset. + pub hash_ids: BTreeSet, +} + +impl MupdateOverrideInfo { + /// The name of the file on the install dataset. + pub const FILE_NAME: &'static str = "mupdate-override.json"; +} diff --git a/installinator-common/src/progress.rs b/installinator-common/src/progress.rs index cafed7a7f40..0c311580c63 100644 --- a/installinator-common/src/progress.rs +++ b/installinator-common/src/progress.rs @@ -294,6 +294,9 @@ pub enum ControlPlaneZonesStepId { /// Writing a zone. Zone { name: String }, + /// Writing the MUPdate override file. + MupdateOverride, + /// Syncing writes to disk. Fsync, diff --git a/installinator/Cargo.toml b/installinator/Cargo.toml index a27208530cf..68bf11b584d 100644 --- a/installinator/Cargo.toml +++ b/installinator/Cargo.toml @@ -29,8 +29,10 @@ itertools.workspace = true libc.workspace = true omicron-common.workspace = true omicron-ddm-admin-client.workspace = true +omicron-uuid-kinds.workspace = true reqwest.workspace = true sha2.workspace = true +serde_json.workspace = true sled-hardware.workspace = true sled-hardware-types.workspace = true sled-storage.workspace = true diff --git a/installinator/src/write.rs b/installinator/src/write.rs index 343a9887a09..d327f266166 100644 --- a/installinator/src/write.rs +++ b/installinator/src/write.rs @@ -20,7 +20,8 @@ use installinator_common::{ StepProgress, StepResult, StepSuccess, UpdateEngine, WriteComponent, WriteError, WriteOutput, WriteSpec, WriteStepId, }; -use omicron_common::disk::M2Slot; +use omicron_common::{disk::M2Slot, update::MupdateOverrideInfo}; +use omicron_uuid_kinds::MupdateOverrideUuid; use sha2::{Digest, Sha256}; use slog::{Logger, info, warn}; use tokio::{ @@ -559,6 +560,8 @@ impl ArtifactsToWrite<'_> { clean_output_directory: destinations.clean_control_plane_dir, output_directory: &destinations.control_plane_dir, zones: self.control_plane_zones, + host_phase_2_id: self.host_phase_2_id, + control_plane_id: self.control_plane_id, }; cx.with_nested_engine(|engine| { inner_cx.register_steps( @@ -592,6 +595,8 @@ struct ControlPlaneZoneWriteContext<'a> { clean_output_directory: bool, output_directory: &'a Utf8Path, zones: &'a ControlPlaneZoneImages, + host_phase_2_id: &'a ArtifactHashId, + control_plane_id: &'a ArtifactHashId, } impl ControlPlaneZoneWriteContext<'_> { @@ -640,6 +645,43 @@ impl ControlPlaneZoneWriteContext<'_> { // successor. let mut transport = StepHandle::ready(transport); + // Write out a file to indicate that installinator has updated the + // dataset. Do this at the very beginning to ensure that installinator's + // presence is recorded even if something goes wrong after this step. + transport = engine + .new_step( + WriteComponent::ControlPlane, + ControlPlaneZonesStepId::MupdateOverride, + "Writing MUPdate override file", + async move |cx| { + let transport = transport.into_value(cx.token()).await; + let mupdate_uuid = MupdateOverrideUuid::new_v4(); + let mupdate_json = + self.mupdate_override_artifact(mupdate_uuid); + + let out_path = self + .output_directory + .join(MupdateOverrideInfo::FILE_NAME); + + write_artifact_impl( + WriteComponent::ControlPlane, + slot, + mupdate_json, + &out_path, + transport, + &cx, + ) + .await?; + + StepSuccess::new(transport) + .with_message(format!( + "{out_path} written with UUID: {mupdate_uuid}", + )) + .into() + }, + ) + .register(); + for (name, data) in &self.zones.zones { let out_path = self.output_directory.join(name); transport = engine @@ -695,6 +737,22 @@ impl ControlPlaneZoneWriteContext<'_> { ) .register(); } + + fn mupdate_override_artifact( + &self, + mupdate_uuid: MupdateOverrideUuid, + ) -> BufList { + // Might be worth writing out individual hash IDs for each zone in the + // future. + let hash_ids = + [self.host_phase_2_id.clone(), self.control_plane_id.clone()] + .into_iter() + .collect(); + let mupdate_override = MupdateOverrideInfo { mupdate_uuid, hash_ids }; + let json_bytes = serde_json::to_vec(&mupdate_override) + .expect("this serialization is infallible"); + BufList::from(json_bytes) + } } fn remove_contents_of(path: &Utf8Path) -> io::Result<()> { diff --git a/sled-agent/Cargo.toml b/sled-agent/Cargo.toml index 0f1af733b25..7273ff00a87 100644 --- a/sled-agent/Cargo.toml +++ b/sled-agent/Cargo.toml @@ -85,6 +85,7 @@ sled-agent-api.workspace = true sled-agent-client.workspace = true sled-agent-config-reconciler.workspace = true sled-agent-types.workspace = true +sled-agent-zone-images.workspace = true sled-diagnostics.workspace = true sled-hardware.workspace = true sled-hardware-types.workspace = true diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index a1f93043b45..ae2398022a0 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -102,14 +102,13 @@ use sled_agent_types::{ sled::SWITCH_ZONE_BASEBOARD_FILE, time_sync::TimeSync, zone_bundle::ZoneBundleCause, }; +use sled_agent_zone_images::ZoneImageSourceResolver; use sled_hardware::SledMode; use sled_hardware::is_gimlet; use sled_hardware::underlay; use sled_hardware_types::Baseboard; use sled_storage::config::MountConfig; -use sled_storage::dataset::{ - CONFIG_DATASET, INSTALL_DATASET, M2_ARTIFACT_DATASET, ZONE_DATASET, -}; +use sled_storage::dataset::{CONFIG_DATASET, ZONE_DATASET}; use sled_storage::manager::StorageHandle; use slog::Logger; use slog_error_chain::InlineErrorChain; @@ -779,8 +778,8 @@ pub struct ServiceManagerInner { switch_zone_bootstrap_address: Ipv6Addr, storage: StorageHandle, zone_bundler: ZoneBundler, + zone_image_source_resolver: ZoneImageSourceResolver, ledger_directory_override: OnceLock, - image_directory_override: OnceLock, system_api: Box, } @@ -991,8 +990,8 @@ impl ServiceManager { .switch_zone_bootstrap_ip, storage, zone_bundler, + zone_image_source_resolver: ZoneImageSourceResolver::new(), ledger_directory_override: OnceLock::new(), - image_directory_override: OnceLock::new(), system_api, }), } @@ -1005,7 +1004,7 @@ impl ServiceManager { #[cfg(all(test, target_os = "illumos"))] fn override_image_directory(&self, path: Utf8PathBuf) { - self.inner.image_directory_override.set(path).unwrap(); + self.zone_image_source_resolver.override_image_directory(path).unwrap(); } pub(crate) fn ddm_reconciler(&self) -> &DdmReconciler { @@ -1725,54 +1724,11 @@ impl ServiceManager { ZoneArgs::Omicron(zone_config) => &zone_config.zone.image_source, ZoneArgs::Switch(_) => &OmicronZoneImageSource::InstallDataset, }; - let zone_image_file_name = match image_source { - OmicronZoneImageSource::InstallDataset => None, - OmicronZoneImageSource::Artifact { hash } => Some(hash.to_string()), - }; let all_disks = self.inner.storage.get_latest_disks().await; - let zone_image_paths = match image_source { - OmicronZoneImageSource::InstallDataset => { - // Look for the image in the ramdisk first - let mut zone_image_paths = - vec![Utf8PathBuf::from("/opt/oxide")]; - // Inject an image path if requested by a test. - if let Some(path) = self.inner.image_directory_override.get() { - zone_image_paths.push(path.clone()); - }; - - // If the boot disk exists, look for the image in the "install" - // dataset there too. - if let Some((_, boot_zpool)) = all_disks.boot_disk() { - zone_image_paths.push(boot_zpool.dataset_mountpoint( - &all_disks.mount_config().root, - INSTALL_DATASET, - )); - } - - zone_image_paths - } - OmicronZoneImageSource::Artifact { .. } => { - // Search both artifact datasets, but look on the boot disk first. - let boot_zpool = - all_disks.boot_disk().map(|(_, boot_zpool)| boot_zpool); - // This iterator starts with the zpool for the boot disk (if it - // exists), and then is followed by all other zpools. - let zpool_iter = boot_zpool.clone().into_iter().chain( - all_disks - .all_m2_zpools() - .into_iter() - .filter(|zpool| Some(zpool) != boot_zpool.as_ref()), - ); - zpool_iter - .map(|zpool| { - zpool.dataset_mountpoint( - &all_disks.mount_config().root, - M2_ARTIFACT_DATASET, - ) - }) - .collect() - } - }; + let file_source = self + .inner + .zone_image_source_resolver + .file_source_for(image_source, &all_disks); let zone_type_str = match &request { ZoneArgs::Omicron(zone_config) => { @@ -1796,14 +1752,14 @@ impl ServiceManager { if let Some(vnic) = bootstrap_vnic { zone_builder = zone_builder.with_bootstrap_vnic(vnic); } - if let Some(file_name) = &zone_image_file_name { + if let Some(file_name) = &file_source.file_name { zone_builder = zone_builder.with_zone_image_file_name(file_name); } let installed_zone = zone_builder .with_log(self.inner.log.clone()) .with_underlay_vnic_allocator(&self.inner.underlay_vnic_allocator) .with_zone_root_path(zone_root_path) - .with_zone_image_paths(zone_image_paths.as_slice()) + .with_zone_image_paths(file_source.search_paths.as_slice()) .with_zone_type(zone_type_str) .with_datasets(datasets.as_slice()) .with_filesystems(&filesystems) diff --git a/sled-agent/zone-images/Cargo.toml b/sled-agent/zone-images/Cargo.toml new file mode 100644 index 00000000000..57c9ac92c63 --- /dev/null +++ b/sled-agent/zone-images/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sled-agent-zone-images" +version = "0.1.0" +edition = "2021" +license = "MPL-2.0" + +[lints] +workspace = true + +[dependencies] +anyhow.workspace = true +camino.workspace = true +nexus-sled-agent-shared.workspace = true +omicron-workspace-hack.workspace = true +sled-storage.workspace = true diff --git a/sled-agent/zone-images/src/lib.rs b/sled-agent/zone-images/src/lib.rs new file mode 100644 index 00000000000..6355188d7e0 --- /dev/null +++ b/sled-agent/zone-images/src/lib.rs @@ -0,0 +1,12 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Management of Omicron zone images within sled-agent. +//! +//! This contains a subset of zone image code at the moment: you're encouraged +//! to move more code into this crate as appropriate. + +mod source_resolver; + +pub use source_resolver::*; diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs new file mode 100644 index 00000000000..bba62aa6672 --- /dev/null +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -0,0 +1,138 @@ +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at https://mozilla.org/MPL/2.0/. + +//! Zone image lookup. + +use camino::Utf8PathBuf; +use nexus_sled_agent_shared::inventory::OmicronZoneImageSource; +use sled_storage::dataset::INSTALL_DATASET; +use sled_storage::dataset::M2_ARTIFACT_DATASET; +use sled_storage::resources::AllDisks; +use std::sync::Mutex; + +/// Places to look for an Omicron zone image. +pub struct ZoneImageFileSource { + /// A custom file name to look for, if provided. + /// + /// The default file name is `.tar.gz`. + pub file_name: Option, + + /// The paths to look for the zone image in. + /// + /// This represents a high-confidence belief, but not a guarantee, that the + /// zone image will be found in one of these locations. + pub search_paths: Vec, +} + +/// Resolves [`OmicronZoneImageSource`] instances into file names and search +/// paths. +pub struct ZoneImageSourceResolver { + // Inner state, guarded by a mutex. + // + // This is mostly a way to ensure that accesses to the resolver are + // serialized. + inner: Mutex, +} + +impl ZoneImageSourceResolver { + pub fn new() -> Self { + ZoneImageSourceResolver { inner: Mutex::new(ResolverInner::new()) } + } + + pub fn override_image_directory(&self, path: Utf8PathBuf) { + self.inner.lock().unwrap().image_directory_override(path); + } + + /// Returns a [`ZoneImageFileSource`] consisting of the file name, plus a + /// list of potential paths to search, for a zone image. + pub fn file_source_for( + &self, + image_source: &OmicronZoneImageSource, + all_disks: &AllDisks, + ) -> ZoneImageFileSource { + let inner = self.inner.lock().unwrap(); + inner.file_source_for(image_source, all_disks) + } +} + +#[derive(Debug)] +struct ResolverInner { + image_directory_override: Option, +} + +impl ResolverInner { + fn new() -> Self { + Self { image_directory_override: None } + } + + fn image_directory_override( + &mut self, + image_directory_override: Utf8PathBuf, + ) { + if let Some(dir) = &self.image_directory_override { + panic!("image_directory_override already set to {dir}"); + } + self.image_directory_override = Some(image_directory_override); + } + + fn file_source_for( + &self, + image_source: &OmicronZoneImageSource, + all_disks: &AllDisks, + ) -> ZoneImageFileSource { + let file_name = match image_source { + OmicronZoneImageSource::InstallDataset => { + // Use the default file name for install-dataset lookups. + None + } + OmicronZoneImageSource::Artifact { hash } => Some(hash.to_string()), + }; + + let search_paths = match image_source { + OmicronZoneImageSource::InstallDataset => { + // Look for the image in the ramdisk first + let mut zone_image_paths = + vec![Utf8PathBuf::from("/opt/oxide")]; + // Inject an image path if requested by a test. + if let Some(path) = &self.image_directory_override { + zone_image_paths.push(path.clone()); + }; + + // If the boot disk exists, look for the image in the "install" + // dataset there too. + if let Some((_, boot_zpool)) = all_disks.boot_disk() { + zone_image_paths.push(boot_zpool.dataset_mountpoint( + &all_disks.mount_config().root, + INSTALL_DATASET, + )); + } + + zone_image_paths + } + OmicronZoneImageSource::Artifact { .. } => { + // Search both artifact datasets, but look on the boot disk first. + let boot_zpool = + all_disks.boot_disk().map(|(_, boot_zpool)| boot_zpool); + // This iterator starts with the zpool for the boot disk (if it + // exists), and then is followed by all other zpools. + let zpool_iter = boot_zpool.clone().into_iter().chain( + all_disks + .all_m2_zpools() + .into_iter() + .filter(|zpool| Some(zpool) != boot_zpool.as_ref()), + ); + zpool_iter + .map(|zpool| { + zpool.dataset_mountpoint( + &all_disks.mount_config().root, + M2_ARTIFACT_DATASET, + ) + }) + .collect() + } + }; + + ZoneImageFileSource { file_name, search_paths } + } +} diff --git a/uuid-kinds/src/lib.rs b/uuid-kinds/src/lib.rs index 93399e7ffde..e10b3f02296 100644 --- a/uuid-kinds/src/lib.rs +++ b/uuid-kinds/src/lib.rs @@ -63,6 +63,7 @@ impl_typed_uuid_kind! { ExternalIp => "external_ip", Instance => "instance", LoopbackAddress => "loopback_address", + MupdateOverride => "mupdate_override", OmicronZone => "service", PhysicalDisk => "physical_disk", Propolis => "propolis", diff --git a/wicketd/tests/integration_tests/updates.rs b/wicketd/tests/integration_tests/updates.rs index aac2a619287..a957bc3e469 100644 --- a/wicketd/tests/integration_tests/updates.rs +++ b/wicketd/tests/integration_tests/updates.rs @@ -13,6 +13,7 @@ use gateway_messages::SpPort; use gateway_test_utils::setup as gateway_setup; use installinator::HOST_PHASE_2_FILE_NAME; use maplit::btreeset; +use omicron_common::update::MupdateOverrideInfo; use tokio::sync::oneshot; use tufaceous_artifact::{ArtifactHashId, ArtifactKind, KnownArtifactKind}; use update_engine::NestedError; @@ -402,6 +403,31 @@ async fn test_installinator_fetch() { assert!(path.is_file(), "{path} was written out"); } + // Ensure that the MUPdate override file was written correctly. + // + // In the mode where we specify a destination directory to write to, + // the install dataset translates to "/zones". + let mupdate_override_path = + dest_path.join("zones").join(MupdateOverrideInfo::FILE_NAME); + assert!( + mupdate_override_path.is_file(), + "{mupdate_override_path} was written out", + ); + + // Ensure that the MUPdate override file can be parsed. + let mupdate_override_bytes = std::fs::read(mupdate_override_path) + .expect("mupdate override file successfully read"); + let override_info = + serde_json::from_slice::(&mupdate_override_bytes) + .expect("mupdate override file successfully deserialized"); + + assert_eq!( + override_info.hash_ids, + btreeset! { + host_phase_2_id, control_plane_id, + } + ); + recv_handle.await.expect("recv_handle succeeded"); wicketd_testctx.teardown().await; From 4e92f93363731b66a43fe44d7b21a0534efbf4eb Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 2 May 2025 11:46:57 -0700 Subject: [PATCH 2/7] rename to ZoneImageZpools, will use this more in upcoming PRs Created using spr 1.3.6-beta.1 --- sled-agent/src/long_running_tasks.rs | 8 +-- .../zone-images/src/mupdate_override.rs | 55 +++++++++---------- sled-agent/zone-images/src/source_resolver.rs | 34 +++--------- 3 files changed, 38 insertions(+), 59 deletions(-) diff --git a/sled-agent/src/long_running_tasks.rs b/sled-agent/src/long_running_tasks.rs index 12a19821919..377be45ef69 100644 --- a/sled-agent/src/long_running_tasks.rs +++ b/sled-agent/src/long_running_tasks.rs @@ -26,9 +26,7 @@ use bootstore::schemes::v0 as bootstore; use illumos_utils::zpool::ZpoolName; use key_manager::{KeyManager, StorageKeyRequester}; use sled_agent_types::zone_bundle::CleanupContext; -use sled_agent_zone_images::{ - ZoneImageSourceResolver, ZoneImageSourceResolverBuilder, -}; +use sled_agent_zone_images::{ZoneImageSourceResolver, ZoneImageZpools}; use sled_hardware::{HardwareManager, SledMode, UnparsedDisk}; use sled_storage::config::MountConfig; use sled_storage::disk::RawSyntheticDisk; @@ -253,12 +251,12 @@ fn make_zone_image_resolver( all_disks: &AllDisks, boot_zpool: &ZpoolName, ) -> ZoneImageSourceResolver { - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: &all_disks.mount_config().root, boot_zpool, all_m2_zpools: all_disks.all_m2_zpools(), }; - builder.build(log) + ZoneImageSourceResolver::new(log, &zpools) } async fn upsert_synthetic_disks_if_needed( diff --git a/sled-agent/zone-images/src/mupdate_override.rs b/sled-agent/zone-images/src/mupdate_override.rs index dd3f98a8a06..27a9d49bd6d 100644 --- a/sled-agent/zone-images/src/mupdate_override.rs +++ b/sled-agent/zone-images/src/mupdate_override.rs @@ -10,7 +10,7 @@ use std::fs; use std::fs::FileType; use std::sync::Arc; -use crate::ZoneImageSourceResolverBuilder; +use crate::ZoneImageZpools; use camino::Utf8Path; use camino::Utf8PathBuf; use id_map::IdMap; @@ -57,11 +57,10 @@ impl AllMupdateOverrides { /// be authoritative). Consider extracting this out into something generic. pub(crate) fn read_all( log: &slog::Logger, - builder: &ZoneImageSourceResolverBuilder<'_>, + zpools: &ZoneImageZpools<'_>, ) -> Self { - let dataset = builder - .boot_zpool - .dataset_mountpoint(builder.root, INSTALL_DATASET); + let dataset = + zpools.boot_zpool.dataset_mountpoint(zpools.root, INSTALL_DATASET); let (boot_disk_path, boot_disk_res) = read_mupdate_override(log, &dataset); @@ -69,14 +68,14 @@ impl AllMupdateOverrides { // Now read the file from all other disks. We attempt to make sure they // match up and will log a warning if they don't, though (until we have // a better story on transient failures) it's not fatal. - let non_boot_zpools = builder + let non_boot_zpools = zpools .all_m2_zpools .iter() - .filter(|&zpool_name| zpool_name != builder.boot_zpool); + .filter(|&zpool_name| zpool_name != zpools.boot_zpool); let non_boot_disks_overrides = non_boot_zpools .map(|zpool_name| { - let dataset = zpool_name - .dataset_mountpoint(builder.root, INSTALL_DATASET); + let dataset = + zpool_name.dataset_mountpoint(zpools.root, INSTALL_DATASET); let (path, res) = read_mupdate_override(log, &dataset); MupdateOverrideNonBootInfo { @@ -91,7 +90,7 @@ impl AllMupdateOverrides { .collect(); Self { - boot_zpool: builder.boot_zpool.clone(), + boot_zpool: zpools.boot_zpool.clone(), boot_disk_path, boot_disk_override: boot_disk_res, non_boot_disk_overrides: non_boot_disks_overrides, @@ -561,12 +560,12 @@ mod tests { .write_str(&serde_json::to_string(&override_info).unwrap()) .unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info) @@ -594,13 +593,13 @@ mod tests { .write_str(&serde_json::to_string(&override_info).unwrap()) .unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info) @@ -633,13 +632,13 @@ mod tests { dir.child(&BOOT_PATHS.install_dataset).create_dir_all().unwrap(); dir.child(&NON_BOOT_PATHS.install_dataset).create_dir_all().unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), None, @@ -675,13 +674,13 @@ mod tests { // Create the directory, but not the override JSON within it. dir.child(&NON_BOOT_PATHS.install_dataset).create_dir_all().unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info) @@ -720,12 +719,12 @@ mod tests { .write_str(&serde_json::to_string(&override_info).unwrap()) .unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), None, @@ -767,12 +766,12 @@ mod tests { .write_str(&serde_json::to_string(&override_info_2).unwrap()) .expect("failed to write override json"); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info), @@ -814,12 +813,12 @@ mod tests { .create_dir_all() .unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap_err(), &dataset_missing_error(&dir_path.join(&BOOT_PATHS.install_dataset)) @@ -856,12 +855,12 @@ mod tests { dir.child(&BOOT_PATHS.install_dataset).touch().unwrap(); dir.child(&NON_BOOT_PATHS.install_dataset).touch().unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap_err(), &dataset_not_dir_error(&dir_path.join(&BOOT_PATHS.install_dataset)) @@ -906,7 +905,7 @@ mod tests { // Read error (empty file). dir.child(&NON_BOOT_3_PATHS.override_json).touch().unwrap(); - let builder = ZoneImageSourceResolverBuilder { + let zpools = ZoneImageZpools { root: dir.path().try_into().unwrap(), boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![ @@ -916,7 +915,7 @@ mod tests { NON_BOOT_3_ZPOOL, ], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &builder); + let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); assert_eq!( overrides.boot_disk_override.as_ref().unwrap_err(), &deserialize_error(dir_path, &BOOT_PATHS.override_json, "",), diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs index 6766b62cdb2..944a76aea54 100644 --- a/sled-agent/zone-images/src/source_resolver.rs +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -30,7 +30,8 @@ pub struct ZoneImageFileSource { pub search_paths: Vec, } -pub struct ZoneImageSourceResolverBuilder<'a> { +/// A description of zpools to examine for zone images. +pub struct ZoneImageZpools<'a> { /// The root directory, typically `/`. pub root: &'a Utf8Path, @@ -42,21 +43,7 @@ pub struct ZoneImageSourceResolverBuilder<'a> { pub all_m2_zpools: Vec, } -impl ZoneImageSourceResolverBuilder<'_> { - /// Converts self into a resolver for zone image sources. - /// - /// This is infallible: any errors that occur are part of the returned - /// `ZoneImageSourceResolver`. This helps ensure that issues creating the - /// resolver don't bring down sled-agent (though they may prevent the - /// creation of zones). - #[inline] - pub fn build(&self, log: &slog::Logger) -> ZoneImageSourceResolver { - ZoneImageSourceResolver::new(log, self) - } -} - -/// Resolves [`OmicronZoneImageSource`] instances into file names and search -/// paths. +/// Turns [`OmicronZoneImageSource`] instances into file names and search paths. #[derive(Clone)] pub struct ZoneImageSourceResolver { // Inner state, guarded by a mutex. @@ -67,11 +54,9 @@ pub struct ZoneImageSourceResolver { } impl ZoneImageSourceResolver { - fn new( - log: &slog::Logger, - builder: &ZoneImageSourceResolverBuilder<'_>, - ) -> Self { - Self { inner: Arc::new(Mutex::new(ResolverInner::new(log, builder))) } + /// Creates a new `ZoneImageSourceResolver`. + pub fn new(log: &slog::Logger, zpools: &ZoneImageZpools<'_>) -> Self { + Self { inner: Arc::new(Mutex::new(ResolverInner::new(log, zpools))) } } pub fn override_image_directory(&self, path: Utf8PathBuf) { @@ -104,13 +89,10 @@ struct ResolverInner { } impl ResolverInner { - fn new( - log: &slog::Logger, - builder: &ZoneImageSourceResolverBuilder<'_>, - ) -> Self { + fn new(log: &slog::Logger, zpools: &ZoneImageZpools<'_>) -> Self { let log = log.new(o!("component" => "ZoneImageSourceResolver")); - let mupdate_overrides = AllMupdateOverrides::read_all(&log, builder); + let mupdate_overrides = AllMupdateOverrides::read_all(&log, zpools); // Log the results. mupdate_overrides.log_results(&log); From dcb4372ec1acead081cb6a99ed1b09fbb09447ea Mon Sep 17 00:00:00 2001 From: Rain Date: Mon, 5 May 2025 20:43:59 +0000 Subject: [PATCH 3/7] update camino-tempfile-ext Created using spr 1.3.6-beta.1 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b5f50ed2be4..d3c5965520b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1068,9 +1068,9 @@ dependencies = [ [[package]] name = "camino-tempfile-ext" -version = "0.2.0" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0ed484a0f760737961ac676efeaffc029948cd7ea329d6c55a4baf936d1cb31" +checksum = "f7b3ab964bd19840be2c70b7795188187a8c1c90006a310b1500bf67b35a80d3" dependencies = [ "anstream", "anstyle", diff --git a/Cargo.toml b/Cargo.toml index ed8172556f7..bb06e74442a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -363,7 +363,7 @@ byteorder = "1.5.0" bytes = "1.10.1" camino = { version = "1.1", features = ["serde1"] } camino-tempfile = "1.1.1" -camino-tempfile-ext = { version = "0.2.0", features = ["assert-color"] } +camino-tempfile-ext = { version = "0.3.0", features = ["assert-color"] } cancel-safe-futures = "0.1.5" cargo_metadata = "0.19.2" chacha20poly1305 = "0.10.1" From cc9b37fd110028198dd05926763d5441ae1e6e72 Mon Sep 17 00:00:00 2001 From: Rain Date: Mon, 5 May 2025 21:37:35 +0000 Subject: [PATCH 4/7] [spr] changes introduced through rebase Created using spr 1.3.6-beta.1 [skip ci] --- sled-agent/zone-images/src/source_resolver.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs index bba62aa6672..b14db8badf5 100644 --- a/sled-agent/zone-images/src/source_resolver.rs +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -41,7 +41,7 @@ impl ZoneImageSourceResolver { } pub fn override_image_directory(&self, path: Utf8PathBuf) { - self.inner.lock().unwrap().image_directory_override(path); + self.inner.lock().unwrap().override_image_directory(path); } /// Returns a [`ZoneImageFileSource`] consisting of the file name, plus a @@ -66,7 +66,7 @@ impl ResolverInner { Self { image_directory_override: None } } - fn image_directory_override( + fn override_image_directory( &mut self, image_directory_override: Utf8PathBuf, ) { From 343ec2214c880f67dc40412c0b5ca825fb79bd61 Mon Sep 17 00:00:00 2001 From: Rain Date: Mon, 5 May 2025 22:16:01 +0000 Subject: [PATCH 5/7] make boot_disks a separate param Created using spr 1.3.6-beta.1 --- sled-agent/src/long_running_tasks.rs | 3 +- sled-agent/src/services.rs | 3 +- .../zone-images/src/mupdate_override.rs | 43 ++++++++++--------- sled-agent/zone-images/src/source_resolver.rs | 24 ++++++++--- 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/sled-agent/src/long_running_tasks.rs b/sled-agent/src/long_running_tasks.rs index 377be45ef69..ce0c3b3f6fe 100644 --- a/sled-agent/src/long_running_tasks.rs +++ b/sled-agent/src/long_running_tasks.rs @@ -253,10 +253,9 @@ fn make_zone_image_resolver( ) -> ZoneImageSourceResolver { let zpools = ZoneImageZpools { root: &all_disks.mount_config().root, - boot_zpool, all_m2_zpools: all_disks.all_m2_zpools(), }; - ZoneImageSourceResolver::new(log, &zpools) + ZoneImageSourceResolver::new(log, &zpools, boot_zpool) } async fn upsert_synthetic_disks_if_needed( diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index 96d01609c92..4d22f29a342 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -5367,11 +5367,10 @@ mod illumos_tests { let (_, boot_zpool) = storage_manager.wait_for_boot_disk().await; let zpools = ZoneImageZpools { root: &all_disks.mount_config().root, - boot_zpool: &boot_zpool, all_m2_zpools: all_disks.all_m2_zpools(), }; let zone_image_resolver = - ZoneImageSourceResolver::new(&log, &zpools); + ZoneImageSourceResolver::new(&log, &zpools, &boot_zpool); LedgerTestHelper { log, diff --git a/sled-agent/zone-images/src/mupdate_override.rs b/sled-agent/zone-images/src/mupdate_override.rs index 6da889280a3..5810766e70a 100644 --- a/sled-agent/zone-images/src/mupdate_override.rs +++ b/sled-agent/zone-images/src/mupdate_override.rs @@ -58,9 +58,10 @@ impl AllMupdateOverrides { pub(crate) fn read_all( log: &slog::Logger, zpools: &ZoneImageZpools<'_>, + boot_zpool: &ZpoolName, ) -> Self { let dataset = - zpools.boot_zpool.dataset_mountpoint(zpools.root, INSTALL_DATASET); + boot_zpool.dataset_mountpoint(zpools.root, INSTALL_DATASET); let (boot_disk_path, boot_disk_res) = read_mupdate_override(log, &dataset); @@ -71,7 +72,7 @@ impl AllMupdateOverrides { let non_boot_zpools = zpools .all_m2_zpools .iter() - .filter(|&zpool_name| zpool_name != zpools.boot_zpool); + .filter(|&zpool_name| zpool_name != boot_zpool); let non_boot_disks_overrides = non_boot_zpools .map(|zpool_name| { let dataset = @@ -90,7 +91,7 @@ impl AllMupdateOverrides { .collect(); Self { - boot_zpool: zpools.boot_zpool.clone(), + boot_zpool: boot_zpool.clone(), boot_disk_path, boot_disk_override: boot_disk_res, non_boot_disk_overrides: non_boot_disks_overrides, @@ -561,10 +562,10 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info) @@ -593,11 +594,11 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info) @@ -631,11 +632,11 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), None, @@ -672,11 +673,11 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info) @@ -716,10 +717,10 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), None, @@ -762,10 +763,10 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap().as_ref(), Some(&override_info), @@ -808,10 +809,10 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap_err(), &dataset_missing_error( @@ -851,10 +852,10 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![BOOT_ZPOOL, NON_BOOT_ZPOOL], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap_err(), &dataset_not_dir_error( @@ -902,7 +903,6 @@ mod tests { let zpools = ZoneImageZpools { root: dir.path(), - boot_zpool: &BOOT_ZPOOL, all_m2_zpools: vec![ BOOT_ZPOOL, NON_BOOT_ZPOOL, @@ -910,7 +910,8 @@ mod tests { NON_BOOT_3_ZPOOL, ], }; - let overrides = AllMupdateOverrides::read_all(&logctx.log, &zpools); + let overrides = + AllMupdateOverrides::read_all(&logctx.log, &zpools, &BOOT_ZPOOL); assert_eq!( overrides.boot_disk_override.as_ref().unwrap_err(), &deserialize_error(dir.path(), &BOOT_PATHS.override_json, "",), diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs index 06b998ffaee..fd18c8a50f0 100644 --- a/sled-agent/zone-images/src/source_resolver.rs +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -35,9 +35,6 @@ pub struct ZoneImageZpools<'a> { /// The root directory, typically `/`. pub root: &'a Utf8Path, - /// The boot disk's zpool name. - pub boot_zpool: &'a ZpoolName, - /// The full set of M.2 zpools that are currently known. Must be non-empty, /// but it can include the boot zpool. pub all_m2_zpools: Vec, @@ -55,8 +52,16 @@ pub struct ZoneImageSourceResolver { impl ZoneImageSourceResolver { /// Creates a new `ZoneImageSourceResolver`. - pub fn new(log: &slog::Logger, zpools: &ZoneImageZpools<'_>) -> Self { - Self { inner: Arc::new(Mutex::new(ResolverInner::new(log, zpools))) } + pub fn new( + log: &slog::Logger, + zpools: &ZoneImageZpools<'_>, + boot_zpool: &ZpoolName, + ) -> Self { + Self { + inner: Arc::new(Mutex::new(ResolverInner::new( + log, zpools, boot_zpool, + ))), + } } pub fn override_image_directory(&self, path: Utf8PathBuf) { @@ -89,10 +94,15 @@ struct ResolverInner { } impl ResolverInner { - fn new(log: &slog::Logger, zpools: &ZoneImageZpools<'_>) -> Self { + fn new( + log: &slog::Logger, + zpools: &ZoneImageZpools<'_>, + boot_zpool: &ZpoolName, + ) -> Self { let log = log.new(o!("component" => "ZoneImageSourceResolver")); - let mupdate_overrides = AllMupdateOverrides::read_all(&log, zpools); + let mupdate_overrides = + AllMupdateOverrides::read_all(&log, zpools, boot_zpool); // Log the results. mupdate_overrides.log_results(&log); From 0bf270e344af6d3b4c0a8b11241c9ff3aa3b2633 Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 6 May 2025 08:41:18 +0000 Subject: [PATCH 6/7] fix clone Created using spr 1.3.6-beta.1 --- sled-agent/zone-images/src/source_resolver.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs index 90313e5ff85..e4ed283875f 100644 --- a/sled-agent/zone-images/src/source_resolver.rs +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -44,6 +44,7 @@ pub struct ZoneImageZpools<'a> { /// paths. /// /// This is cheaply cloneable. +#[derive(Clone)] pub struct ZoneImageSourceResolver { // Inner state, guarded by a mutex. inner: Arc>, From 4d908d1bb4e0e07c570caee16a47d6ea13525efc Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 6 May 2025 09:06:15 +0000 Subject: [PATCH 7/7] [spr] changes introduced through rebase Created using spr 1.3.6-beta.1 [skip ci] --- sled-agent/src/services.rs | 8 ++++---- sled-agent/zone-images/src/source_resolver.rs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/sled-agent/src/services.rs b/sled-agent/src/services.rs index a39d73238d2..c36953d20a9 100644 --- a/sled-agent/src/services.rs +++ b/sled-agent/src/services.rs @@ -778,7 +778,7 @@ pub struct ServiceManagerInner { switch_zone_bootstrap_address: Ipv6Addr, storage: StorageHandle, zone_bundler: ZoneBundler, - zone_image_source_resolver: ZoneImageSourceResolver, + zone_image_resolver: ZoneImageSourceResolver, ledger_directory_override: OnceLock, system_api: Box, } @@ -990,7 +990,7 @@ impl ServiceManager { .switch_zone_bootstrap_ip, storage, zone_bundler, - zone_image_source_resolver: ZoneImageSourceResolver::new(), + zone_image_resolver: ZoneImageSourceResolver::new(), ledger_directory_override: OnceLock::new(), system_api, }), @@ -1004,7 +1004,7 @@ impl ServiceManager { #[cfg(all(test, target_os = "illumos"))] fn override_image_directory(&self, path: Utf8PathBuf) { - self.zone_image_source_resolver.override_image_directory(path).unwrap(); + self.inner.zone_image_resolver.override_image_directory(path); } pub(crate) fn ddm_reconciler(&self) -> &DdmReconciler { @@ -1727,7 +1727,7 @@ impl ServiceManager { let all_disks = self.inner.storage.get_latest_disks().await; let file_source = self .inner - .zone_image_source_resolver + .zone_image_resolver .file_source_for(image_source, &all_disks); let zone_type_str = match &request { diff --git a/sled-agent/zone-images/src/source_resolver.rs b/sled-agent/zone-images/src/source_resolver.rs index c1e920dd58e..cf6d7faff35 100644 --- a/sled-agent/zone-images/src/source_resolver.rs +++ b/sled-agent/zone-images/src/source_resolver.rs @@ -43,6 +43,9 @@ impl ZoneImageSourceResolver { } } + /// Overrides the image directory with another one. + /// + /// Intended for testing. pub fn override_image_directory(&self, path: Utf8PathBuf) { self.inner.lock().unwrap().override_image_directory(path); }