Skip to content

Commit adecbd6

Browse files
committed
Move support bundle collection into a shared crate
Lifts `nexus/src/app/background/tasks/support_bundle/` (the mechanism layer) into a new top-level crate `support-bundle-collection` so that both Nexus and omdb can call it. No logic changes; pure relocation plus import rewriting.
1 parent 1afa67a commit adecbd6

22 files changed

Lines changed: 276 additions & 135 deletions

File tree

Cargo.lock

Lines changed: 41 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ members = [
161161
"sled-storage",
162162
"sled-storage/zfs-test-harness",
163163
"sp-sim",
164+
"support-bundle-collection",
164165
"test-utils",
165166
"trust-quorum",
166167
"trust-quorum/gfss",
@@ -347,6 +348,7 @@ default-members = [
347348
"sled-storage",
348349
"sled-storage/zfs-test-harness",
349350
"sp-sim",
351+
"support-bundle-collection",
350352
"trust-quorum",
351353
"trust-quorum/gfss",
352354
"trust-quorum/protocol",
@@ -823,6 +825,7 @@ strum = { version = "0.27.2", features = [ "derive" ] }
823825
subprocess = "0.2.9"
824826
subtle = "2.6.1"
825827
supports-color = "3.0.2"
828+
support-bundle-collection = { path = "support-bundle-collection" }
826829
support-bundle-viewer = "0.1.2"
827830
swrite = "0.1.0"
828831
sync-ptr = "0.1.4"

dev-tools/ls-apis/tests/api_dependencies.out

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ Management Gateway Service (client: gateway-client)
4949
consumed by: dpd (dendrite/dpd) via 1 path
5050
consumed by: lldpd (lldp/lldpd) via 1 path
5151
consumed by: mgd (maghemite/mgd) via 1 path
52-
consumed by: omicron-nexus (omicron/nexus) via 5 paths
52+
consumed by: omicron-nexus (omicron/nexus) via 6 paths
5353
consumed by: omicron-sled-agent (omicron/sled-agent) via 1 path
5454
consumed by: wicketd (omicron/wicketd) via 3 paths
5555

@@ -96,7 +96,7 @@ Repo Depot API (client: repo-depot-client)
9696
consumed by: omicron-sled-agent (omicron/sled-agent) via 1 path
9797

9898
Sled Agent (client: sled-agent-client)
99-
consumed by: omicron-nexus (omicron/nexus) via 8 paths
99+
consumed by: omicron-nexus (omicron/nexus) via 9 paths
100100

101101
Wicketd (client: wicketd-client)
102102

nexus/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,7 @@ raw-cpuid = { workspace = true, features = ["std"] }
159159
rustls = { workspace = true }
160160
rustls-pemfile = { workspace = true }
161161
scim2-rs.workspace = true
162+
support-bundle-collection.workspace = true
162163
update-common.workspace = true
163164
update-engine.workspace = true
164165
omicron-workspace-hack.workspace = true

nexus/src/app/background/tasks/mod.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,6 @@ pub mod region_snapshot_replacement_step;
4949
pub mod saga_recovery;
5050
pub mod service_firewall_rules;
5151
pub mod session_cleanup;
52-
pub mod support_bundle;
5352
pub mod support_bundle_collector;
5453
pub mod sync_service_zone_nat;
5554
pub mod sync_switch_configuration;

nexus/src/app/background/tasks/support_bundle_collector.rs

Lines changed: 8 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,8 @@
66
77
use crate::app::background::BackgroundTask;
88
use anyhow::Context;
9-
use camino::Utf8DirEntry;
10-
use camino::Utf8Path;
119
use camino_tempfile::Utf8TempDir;
1210
use camino_tempfile::tempdir_in;
13-
use camino_tempfile::tempfile_in;
1411
use futures::FutureExt;
1512
use futures::future::BoxFuture;
1613
use internal_dns_resolver::Resolver;
@@ -38,16 +35,14 @@ use slog_error_chain::InlineErrorChain;
3835
use std::io::Write;
3936
use std::num::NonZeroU64;
4037
use std::sync::Arc;
38+
use support_bundle_collection::BundleCollection;
39+
use support_bundle_collection::BundleInfo;
40+
use support_bundle_collection::zip::bundle_to_zipfile;
4141
use tokio::io::AsyncReadExt;
4242
use tokio::io::AsyncSeekExt;
4343
use tokio::io::SeekFrom;
4444
use tokio_util::sync::CancellationToken;
4545
use tufaceous_artifact::ArtifactHash;
46-
use zip::ZipWriter;
47-
use zip::write::FullFileOptions;
48-
49-
use super::support_bundle::collection::BundleCollection;
50-
use super::support_bundle::collection::BundleInfo;
5146

5247
/// We use "/var/tmp" to use Nexus' filesystem for temporary storage,
5348
/// rather than "/tmp", which would keep this collected data in-memory.
@@ -481,7 +476,10 @@ impl SupportBundleCollector {
481476
dir: Utf8TempDir,
482477
) -> anyhow::Result<()> {
483478
// Create the zipfile as a temporary file
484-
let mut zipfile = tokio::fs::File::from_std(bundle_to_zipfile(&dir)?);
479+
let mut zipfile = tokio::fs::File::from_std(bundle_to_zipfile(
480+
&dir,
481+
camino::Utf8Path::new(TEMPDIR),
482+
)?);
485483
let total_len = zipfile.metadata().await?.len();
486484

487485
// Collect the hash locally before we send it over the network
@@ -635,67 +633,6 @@ async fn check_for_cancellation(
635633
}
636634
}
637635

638-
// Takes a directory "dir", and zips the contents into a single zipfile.
639-
fn bundle_to_zipfile(dir: &Utf8TempDir) -> anyhow::Result<std::fs::File> {
640-
let tempfile = tempfile_in(TEMPDIR)?;
641-
let mut zip = ZipWriter::new(tempfile);
642-
643-
recursively_add_directory_to_zipfile(&mut zip, dir.path(), dir.path())?;
644-
645-
Ok(zip.finish()?)
646-
}
647-
648-
fn recursively_add_directory_to_zipfile(
649-
zip: &mut ZipWriter<std::fs::File>,
650-
root_path: &Utf8Path,
651-
dir_path: &Utf8Path,
652-
) -> anyhow::Result<()> {
653-
// Readdir might return entries in a non-deterministic order.
654-
// Let's sort it for the zipfile, to be nice.
655-
let mut entries = dir_path
656-
.read_dir_utf8()?
657-
.filter_map(Result::ok)
658-
.collect::<Vec<Utf8DirEntry>>();
659-
entries.sort_by(|a, b| a.file_name().cmp(&b.file_name()));
660-
661-
for entry in &entries {
662-
// Remove the "/tmp/..." prefix from the path when we're storing it in the
663-
// zipfile.
664-
let dst = entry.path().strip_prefix(root_path)?;
665-
666-
let file_type = entry.file_type()?;
667-
if file_type.is_file() {
668-
let src = entry.path();
669-
670-
let zip_time = entry
671-
.path()
672-
.metadata()
673-
.and_then(|m| m.modified())
674-
.ok()
675-
.and_then(|sys_time| jiff::Zoned::try_from(sys_time).ok())
676-
.and_then(|zoned| {
677-
zip::DateTime::try_from(zoned.datetime()).ok()
678-
})
679-
.unwrap_or_else(zip::DateTime::default);
680-
681-
let opts = FullFileOptions::default()
682-
.last_modified_time(zip_time)
683-
.compression_method(zip::CompressionMethod::Deflated)
684-
.large_file(true);
685-
686-
zip.start_file_from_path(dst, opts)?;
687-
let mut file = std::fs::File::open(&src)?;
688-
std::io::copy(&mut file, zip)?;
689-
}
690-
if file_type.is_dir() {
691-
let opts = FullFileOptions::default();
692-
zip.add_directory_from_path(dst, opts)?;
693-
recursively_add_directory_to_zipfile(zip, root_path, entry.path())?;
694-
}
695-
}
696-
Ok(())
697-
}
698-
699636
async fn sha2_hash(file: &mut tokio::fs::File) -> anyhow::Result<ArtifactHash> {
700637
let mut buf = vec![0u8; 65536];
701638
let mut ctx = Sha256::new();
@@ -757,7 +694,6 @@ impl BackgroundTask for SupportBundleCollector {
757694
mod test {
758695
use super::*;
759696

760-
use crate::app::background::tasks::support_bundle::perfetto;
761697
use crate::app::support_bundles::SupportBundleQueryType;
762698
use http_body_util::BodyExt;
763699
use nexus_db_model::PhysicalDisk;
@@ -788,6 +724,7 @@ mod test {
788724
};
789725
use sled_agent_types::inventory::ZpoolHealth;
790726
use std::num::NonZeroU64;
727+
use support_bundle_collection::perfetto;
791728
use uuid::Uuid;
792729

793730
type ControlPlaneTestContext =
@@ -2137,28 +2074,4 @@ mod test {
21372074
SupportBundleCollectionStepStatus::Skipped
21382075
);
21392076
}
2140-
2141-
// Ensure that we can convert a temporary directory into a zipfile
2142-
#[test]
2143-
fn test_zipfile_creation() {
2144-
let dir = camino_tempfile::tempdir().unwrap();
2145-
2146-
std::fs::create_dir_all(dir.path().join("dir-a")).unwrap();
2147-
std::fs::create_dir_all(dir.path().join("dir-b")).unwrap();
2148-
std::fs::write(dir.path().join("dir-a").join("file-a"), "some data")
2149-
.unwrap();
2150-
std::fs::write(dir.path().join("file-b"), "more data").unwrap();
2151-
2152-
let zipfile = bundle_to_zipfile(&dir)
2153-
.expect("Should have been able to bundle zipfile");
2154-
let archive = zip::read::ZipArchive::new(zipfile).unwrap();
2155-
2156-
// We expect the order to be deterministically alphabetical
2157-
let mut names = archive.file_names();
2158-
assert_eq!(names.next(), Some("dir-a/"));
2159-
assert_eq!(names.next(), Some("dir-a/file-a"));
2160-
assert_eq!(names.next(), Some("dir-b/"));
2161-
assert_eq!(names.next(), Some("file-b"));
2162-
assert_eq!(names.next(), None);
2163-
}
21642077
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[package]
2+
name = "support-bundle-collection"
3+
version = "0.1.0"
4+
edition.workspace = true
5+
6+
[lints]
7+
workspace = true
8+
9+
[build-dependencies]
10+
omicron-rpaths.workspace = true
11+
12+
[dependencies]
13+
anyhow.workspace = true
14+
base64.workspace = true
15+
camino.workspace = true
16+
camino-tempfile.workspace = true
17+
chrono.workspace = true
18+
dropshot.workspace = true
19+
futures.workspace = true
20+
gateway-client.workspace = true
21+
gateway-types.workspace = true
22+
internal-dns-resolver.workspace = true
23+
internal-dns-types.workspace = true
24+
jiff.workspace = true
25+
nexus-db-model.workspace = true
26+
nexus-db-queries.workspace = true
27+
nexus-networking.workspace = true
28+
nexus-reconfigurator-preparation.workspace = true
29+
nexus-types.workspace = true
30+
omicron-common.workspace = true
31+
omicron-uuid-kinds.workspace = true
32+
parallel-task-set.workspace = true
33+
# See omicron-rpaths for more about the "pq-sys" dependency.
34+
pq-sys = "*"
35+
serde.workspace = true
36+
serde_json.workspace = true
37+
sha2.workspace = true
38+
sled-agent-client.workspace = true
39+
slog.workspace = true
40+
slog-error-chain.workspace = true
41+
tokio.workspace = true
42+
tokio-util.workspace = true
43+
tufaceous-artifact.workspace = true
44+
uuid.workspace = true
45+
zip.workspace = true
46+
47+
omicron-workspace-hack.workspace = true
File renamed without changes.

nexus/src/app/background/tasks/support_bundle/mod.rs renamed to support-bundle-collection/build.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,9 @@
22
// License, v. 2.0. If a copy of the MPL was not distributed with this
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

5-
//! Support bundle related types and utilities
6-
7-
mod cache;
8-
pub mod collection;
9-
pub mod perfetto;
10-
mod step;
11-
mod steps;
5+
// See omicron-rpaths for documentation.
6+
// NOTE: This file MUST be kept in sync with the other build.rs files in this
7+
// repository.
8+
fn main() {
9+
omicron_rpaths::configure_default_omicron_rpaths();
10+
}

nexus/src/app/background/tasks/support_bundle/cache.rs renamed to support-bundle-collection/src/cache.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
//! This is used to share data which may be used by multiple
88
//! otherwise independent steps.
99
10-
use crate::app::background::tasks::support_bundle::collection::BundleCollection;
10+
use crate::collection::BundleCollection;
1111

1212
use gateway_client::Client as MgsClient;
1313
use internal_dns_types::names::ServiceName;

0 commit comments

Comments
 (0)