diff --git a/illumos-utils/src/zfs.rs b/illumos-utils/src/zfs.rs index f28c3372280..9f2abd2a369 100644 --- a/illumos-utils/src/zfs.rs +++ b/illumos-utils/src/zfs.rs @@ -1308,7 +1308,7 @@ impl Zfs { .collect::, GetValueError>>()? .join(","); - cmd.args(&[ZFS, "get", "-Ho", "value"]); + cmd.args(&[ZFS, "get", "-Hpo", "value"]); if let Some(source) = source { cmd.args(&["-s", &source.to_string()]); } diff --git a/sled-agent/src/sled_agent.rs b/sled-agent/src/sled_agent.rs index bf2c693b25e..646e28f3446 100644 --- a/sled-agent/src/sled_agent.rs +++ b/sled-agent/src/sled_agent.rs @@ -703,7 +703,7 @@ impl SledAgent { pub(crate) fn as_support_bundle_logs(&self) -> SupportBundleLogs<'_> { SupportBundleLogs::new( &self.log, - self.inner.config_reconciler.internal_disks_rx(), + self.inner.config_reconciler.available_datasets_rx(), ) } diff --git a/sled-agent/src/support_bundle/logs.rs b/sled-agent/src/support_bundle/logs.rs index c68a3bdedde..48f9b816f78 100644 --- a/sled-agent/src/support_bundle/logs.rs +++ b/sled-agent/src/support_bundle/logs.rs @@ -6,8 +6,10 @@ use camino_tempfile::tempfile_in; use dropshot::HttpError; +use futures::StreamExt; +use futures::stream::FuturesUnordered; use range_requests::make_get_response; -use sled_agent_config_reconciler::InternalDisksReceiver; +use sled_agent_config_reconciler::AvailableDatasetsReceiver; use slog::Logger; use slog_error_chain::InlineErrorChain; use tokio::io::AsyncSeekExt; @@ -43,15 +45,15 @@ impl From for HttpError { pub struct SupportBundleLogs<'a> { log: &'a Logger, - internal_disks_rx: &'a InternalDisksReceiver, + available_datasets_rx: AvailableDatasetsReceiver, } impl<'a> SupportBundleLogs<'a> { pub fn new( log: &'a Logger, - internal_disks_rx: &'a InternalDisksReceiver, + available_datasets_rx: AvailableDatasetsReceiver, ) -> Self { - Self { log, internal_disks_rx } + Self { log, available_datasets_rx } } /// Get a list of zones on a sled containing logs that we want to include in @@ -78,12 +80,53 @@ impl<'a> SupportBundleLogs<'a> { where Z: Into, { - // We are using an M.2 device for temporary storage to assemble a zip - // file made up of all of the discovered zone's logs. - let current_internal_disks = self.internal_disks_rx.current(); - let mut m2_debug_datasets = current_internal_disks.all_debug_datasets(); - let tempdir = m2_debug_datasets.next().ok_or(Error::MissingStorage)?; - let mut tempfile = tempfile_in(tempdir)?; + // Attempt to find a U.2 device with the most available free space + // for temporary storage to assemble a zip file made up of all of the + // discovered zone's logs. + let mounted_debug_datasets = + self.available_datasets_rx.all_mounted_debug_datasets(); + let storage_paths_to_size: Vec<_> = mounted_debug_datasets + .into_iter() + .map(|dataset_path| { + let path = dataset_path.path; + async move { + match illumos_utils::zfs::Zfs::get_value( + path.as_str(), + "available", + ) + .await + { + Ok(size_str) => match size_str.parse::() { + Ok(size) => Some((path, size)), + Err(e) => { + warn!( + &self.log, + "failed to parse available size for the \ + dataset at path {path}: {e}" + ); + None + } + }, + Err(e) => { + warn!( + &self.log, + "failed to get available size for the dataset \ + at path {path}: {e}" + ); + None + } + } + } + }) + .collect::>() + .collect() + .await; + let (largest_avail_space, _) = storage_paths_to_size + .into_iter() + .flatten() + .max_by_key(|(_, size)| *size) + .ok_or(Error::MissingStorage)?; + let mut tempfile = tempfile_in(largest_avail_space)?; let log = self.log.clone(); let zone = zone.into(); diff --git a/sled-storage/src/resources.rs b/sled-storage/src/resources.rs index 0e63fca65e7..5748a963a61 100644 --- a/sled-storage/src/resources.rs +++ b/sled-storage/src/resources.rs @@ -209,15 +209,6 @@ impl AllDisks { .collect() } - /// Return the directories that can be used for temporary sled-diagnostics - /// file storage. - pub fn all_sled_diagnostics_directories(&self) -> Vec { - // These directories are currently used for tempfile storage when - // zipping up zone logs before shuffling them off to a nexus collecting - // a support bundle. - self.all_m2_mountpoints(M2_DEBUG_DATASET).into_iter().collect() - } - /// Returns an iterator over all managed disks. pub fn iter_managed(&self) -> impl Iterator { self.inner.values.iter().filter_map(|(identity, disk)| match disk {