Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 115 additions & 34 deletions dev-tools/omdb/src/bin/omdb/nexus.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ use nexus_types::internal_api::background::CapacityMetricsStatus;
use nexus_types::internal_api::background::DatasetRendezvousOutcome;
use nexus_types::internal_api::background::DatasetRendezvousStats;
use nexus_types::internal_api::background::DatasetsRendezvousStats;
use nexus_types::internal_api::background::DendriteSubnetDetails;
use nexus_types::internal_api::background::EreporterStatus;
use nexus_types::internal_api::background::FmAnalysisStatus;
use nexus_types::internal_api::background::FmConfigLoadStatus;
Expand All @@ -89,6 +90,7 @@ use nexus_types::internal_api::background::SitrepGcStatus;
use nexus_types::internal_api::background::SitrepLoadStatus;
use nexus_types::internal_api::background::SledBlueprintAvailabilityRendezvousOutcome;
use nexus_types::internal_api::background::SledBlueprintAvailabilityRendezvousStats;
use nexus_types::internal_api::background::SledSubnetDetails;
use nexus_types::internal_api::background::SupportBundleActivationReport;
use nexus_types::internal_api::background::SupportBundleCleanupReport;
use nexus_types::internal_api::background::SupportBundleCollectionStepStatus;
Expand Down Expand Up @@ -2481,44 +2483,58 @@ fn print_task_attached_subnet_manager_status(details: &serde_json::Value) {
"warning: failed to interpret task details: {:?}: {:?}",
error, details
),
Ok(AttachedSubnetManagerStatus { db_error, dendrite, sled }) => {
if let Some(err) = db_error {
println!(
" error accessing database to list attached subnets:"
);
println!(" {err}");
}
if dendrite.is_empty() {
println!(" no dendrite instances found");
} else {
for (switch_slot, details) in dendrite.iter() {
println!(" dendrite instance on switch {switch_slot:?}");
println!(
" n_subnets_removed={}",
details.n_subnets_removed
);
println!(
" n_subnets_added={}",
details.n_subnets_added
);
println!(
" n_subnets_total={}",
details.n_total_subnets
);
}
}
if sled.is_empty() {
println!(" no sleds found");
} else {
for (sled_id, details) in sled.iter() {
println!(" sled {sled_id}");
println!(" n_subnets={}", details.n_subnets);
}
}
Ok(status) => {
print!("{}", AttachedSubnetManagerStatusDisplay(&status));
}
};
}

struct AttachedSubnetManagerStatusDisplay<'a>(&'a AttachedSubnetManagerStatus);

impl std::fmt::Display for AttachedSubnetManagerStatusDisplay<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let AttachedSubnetManagerStatus { db_error, dendrite, sled } = self.0;
if let Some(err) = db_error {
writeln!(
f,
" error accessing database to list attached subnets:"
)?;
writeln!(f, " {err}")?;
}
if dendrite.is_empty() {
writeln!(f, " no dendrite instances found")?;
} else {
// Sort the data by switch slot to ensure stable output.
let mut dendrite: Vec<_> = dendrite.iter().collect();
Comment on lines +2507 to +2508

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the small change.

dendrite.sort_unstable_by_key(|(switch_slot, _)| **switch_slot);
for (switch_slot, details) in dendrite {
let DendriteSubnetDetails {
n_subnets_added,
n_subnets_removed,
n_total_subnets,
errors: _,
} = details;
writeln!(f, " dendrite instance on switch {switch_slot:?}")?;
writeln!(f, " n_subnets_removed={n_subnets_removed}")?;
writeln!(f, " n_subnets_added={n_subnets_added}")?;
writeln!(f, " n_subnets_total={n_total_subnets}")?;
}
}
if sled.is_empty() {
writeln!(f, " no sleds found")?;
} else {
let mut sled: Vec<_> = sled.iter().collect();
sled.sort_unstable_by_key(|(sled_id, _)| **sled_id);
for (sled_id, details) in sled {
let SledSubnetDetails { n_subnets, errors: _ } = details;
writeln!(f, " sled {sled_id}")?;
writeln!(f, " n_subnets={n_subnets}")?;
}
}
Ok(())
}
}

fn print_task_read_only_region_replacement_start(details: &serde_json::Value) {
match serde_json::from_value::<ReadOnlyRegionReplacementStartStatus>(
details.clone(),
Expand Down Expand Up @@ -6088,7 +6104,9 @@ mod tests {
use omicron_uuid_kinds::AlertUuid;
use omicron_uuid_kinds::RackUuid;
use omicron_uuid_kinds::WebhookDeliveryUuid;
use sled_agent_types::early_networking::SwitchSlot;
use std::collections::BTreeMap;
use std::collections::HashMap;

#[test]
fn test_ereporter_status_totals_display() {
Expand Down Expand Up @@ -6190,6 +6208,69 @@ mod tests {
);
}

#[test]
fn test_attached_subnet_manager_status_display() {
// In this test:
//
// * There are two entries in `dendrite` to exercise
// the sorting in AttachedSubnetManagerStatusDisplay.
// * Some entries have errors. These errors are not
// currently displayed, but will be in an upcoming
// commit.
let sled1 = SledUuid::from_u128(0x1b2b4c4f_42a5_4e3c_8b28_a1c1f2f3a0b1);
let sled2 = SledUuid::from_u128(0x9d8e2f61_7c0d_4b6a_9e5f_3a4b5c6d7e8f);
let status = AttachedSubnetManagerStatus {
db_error: None,
dendrite: HashMap::from([
(
SwitchSlot::Switch1,
DendriteSubnetDetails {
n_subnets_added: 0,
n_subnets_removed: 1,
n_total_subnets: 2,
errors: vec!["failed to create subnet".to_string()],
},
),
(
SwitchSlot::Switch0,
DendriteSubnetDetails {
n_subnets_added: 3,
n_subnets_removed: 0,
n_total_subnets: 3,
errors: Vec::new(),
},
),
]),
sled: HashMap::from([
(
sled2,
SledSubnetDetails {
n_subnets: 1,
errors: vec![
"duplicate subnet".to_string(),
"failed to send attached subnets".to_string(),
],
},
),
(sled1, SledSubnetDetails { n_subnets: 2, errors: Vec::new() }),
]),
};
expectorate::assert_contents(
"tests/output/attached-subnet-manager-status.txt",
&AttachedSubnetManagerStatusDisplay(&status).to_string(),
);

let db_error = AttachedSubnetManagerStatus {
db_error: Some("database unavailable".to_string()),
dendrite: HashMap::new(),
sled: HashMap::new(),
};
expectorate::assert_contents(
"tests/output/attached-subnet-manager-status-db-error.txt",
&AttachedSubnetManagerStatusDisplay(&db_error).to_string(),
);
}

#[test]
fn test_last_pass_success_display_distinct_counts() {
let success = LastPassSuccess {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
error accessing database to list attached subnets:
database unavailable
no dendrite instances found
no sleds found
12 changes: 12 additions & 0 deletions dev-tools/omdb/tests/output/attached-subnet-manager-status.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
dendrite instance on switch switch0
n_subnets_removed=0
n_subnets_added=3
n_subnets_total=3
dendrite instance on switch switch1
n_subnets_removed=1
n_subnets_added=0
n_subnets_total=2
sled 1b2b4c4f-42a5-4e3c-8b28-a1c1f2f3a0b1
n_subnets=2
sled 9d8e2f61-7c0d-4b6a-9e5f-3a4b5c6d7e8f
n_subnets=1
Loading