Skip to content

Commit c2191f0

Browse files
committed
nexus-types: add SupportBundleRequest type and Case field
Add SupportBundleRequest to fm::case with data_selection support. Add support_bundles_requested field to Case and iterator to Sitrep. Add Serialize/Deserialize derives to support_bundle types (needed because Case derives Serialize). Add BundleDataSelection::iter() for per-variant decomposition.
1 parent 08b5f84 commit c2191f0

5 files changed

Lines changed: 76 additions & 6 deletions

File tree

nexus/db-model/src/fm/case.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ impl CaseMetadata {
5858
de,
5959
comment,
6060
alerts_requested: _,
61+
support_bundles_requested: _,
6162
ereports: _,
6263
} = case;
6364
Self {

nexus/db-queries/src/db/datastore/fm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -385,6 +385,7 @@ impl DataStore {
385385
comment,
386386
ereports,
387387
alerts_requested,
388+
support_bundles_requested: iddqd::IdOrdMap::new(),
388389
}
389390
}));
390391
}

nexus/types/src/fm.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,17 @@ impl Sitrep {
8181
case.alerts_requested.iter().map(move |alert| (case_id, alert))
8282
})
8383
}
84+
85+
/// Iterate over all support bundles requested by cases in this sitrep.
86+
pub fn support_bundles_requested(
87+
&self,
88+
) -> impl Iterator<Item = (CaseUuid, &'_ case::SupportBundleRequest)> + '_
89+
{
90+
self.cases.iter().flat_map(|case| {
91+
let case_id = case.id;
92+
case.support_bundles_requested.iter().map(move |req| (case_id, req))
93+
})
94+
}
8495
}
8596

8697
/// Metadata describing a sitrep.

nexus/types/src/fm/case.rs

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,11 @@
55
use crate::alert::AlertClass;
66
use crate::fm::DiagnosisEngineKind;
77
use crate::fm::Ereport;
8+
use crate::support_bundle::BundleDataSelection;
89
use iddqd::{IdOrdItem, IdOrdMap};
9-
use omicron_uuid_kinds::{AlertUuid, CaseEreportUuid, CaseUuid, SitrepUuid};
10+
use omicron_uuid_kinds::{
11+
AlertUuid, CaseEreportUuid, CaseUuid, SitrepUuid, SupportBundleUuid,
12+
};
1013
use serde::{Deserialize, Serialize};
1114
use std::fmt;
1215
use std::sync::Arc;
@@ -21,6 +24,7 @@ pub struct Case {
2124

2225
pub ereports: IdOrdMap<CaseEreport>,
2326
pub alerts_requested: IdOrdMap<AlertRequest>,
27+
pub support_bundles_requested: IdOrdMap<SupportBundleRequest>,
2428

2529
pub comment: String,
2630
}
@@ -88,6 +92,23 @@ impl iddqd::IdOrdItem for AlertRequest {
8892
iddqd::id_upcast!();
8993
}
9094

95+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
96+
pub struct SupportBundleRequest {
97+
pub id: SupportBundleUuid,
98+
pub requested_sitrep_id: SitrepUuid,
99+
pub reason: String,
100+
pub data_selection: Option<BundleDataSelection>,
101+
}
102+
103+
impl iddqd::IdOrdItem for SupportBundleRequest {
104+
type Key<'a> = &'a SupportBundleUuid;
105+
fn key(&self) -> Self::Key<'_> {
106+
&self.id
107+
}
108+
109+
iddqd::id_upcast!();
110+
}
111+
91112
struct DisplayCase<'a> {
92113
case: &'a Case,
93114
indent: usize,
@@ -120,6 +141,7 @@ impl fmt::Display for DisplayCase<'_> {
120141
ereports,
121142
comment,
122143
alerts_requested,
144+
support_bundles_requested,
123145
},
124146
indent,
125147
sitrep_id,
@@ -234,6 +256,34 @@ impl fmt::Display for DisplayCase<'_> {
234256
}
235257
}
236258

259+
if !support_bundles_requested.is_empty() {
260+
writeln!(f, "\n{:>indent$}support bundles requested:", "")?;
261+
writeln!(f, "{:>indent$}-------------------------", "")?;
262+
263+
let indent = indent + 2;
264+
for SupportBundleRequest {
265+
id,
266+
requested_sitrep_id,
267+
reason,
268+
data_selection: _,
269+
} in support_bundles_requested.iter()
270+
{
271+
const REASON: &str = "reason:";
272+
const REQUESTED_IN: &str = "requested in:";
273+
274+
const WIDTH: usize = const_max_len(&[REASON, REQUESTED_IN]);
275+
276+
writeln!(f, "{BULLET:>indent$}bundle {id}",)?;
277+
writeln!(f, "{:>indent$}{REASON:<WIDTH$} {reason}", "",)?;
278+
writeln!(
279+
f,
280+
"{:>indent$}{REQUESTED_IN:<WIDTH$} {requested_sitrep_id}{}\n",
281+
"",
282+
this_sitrep(*requested_sitrep_id)
283+
)?;
284+
}
285+
}
286+
237287
writeln!(f)?;
238288

239289
Ok(())
@@ -357,6 +407,7 @@ mod tests {
357407
de: DiagnosisEngineKind::PowerShelf,
358408
ereports,
359409
alerts_requested,
410+
support_bundles_requested: IdOrdMap::new(),
360411
comment: "Power shelf rectifier added and removed here :-)"
361412
.to_string(),
362413
};

nexus/types/src/support_bundle.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,12 @@
1010
use chrono::{DateTime, Utc};
1111
use omicron_common::api::external::Error;
1212
use omicron_uuid_kinds::SledUuid;
13+
use serde::{Deserialize, Serialize};
1314
use std::collections::HashMap;
1415
use std::collections::HashSet;
1516

1617
/// A set of filters for fetching ereports.
17-
#[derive(Clone, Debug, Default, Eq, PartialEq)]
18+
#[derive(Clone, Debug, Default, Eq, PartialEq, Serialize, Deserialize)]
1819
pub struct EreportFilters {
1920
/// If present, include only ereports that were collected at the specified
2021
/// timestamp or later.
@@ -52,7 +53,7 @@ impl EreportFilters {
5253
}
5354

5455
/// Describes the category of support bundle data.
55-
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
56+
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq, Serialize, Deserialize)]
5657
pub enum BundleDataCategory {
5758
/// Collects reconfigurator state (some of the latest blueprints,
5859
/// information about the target blueprint).
@@ -74,7 +75,7 @@ pub enum BundleDataCategory {
7475
/// For categories without additional parameters, the variant is a unit variant.
7576
/// For categories that can be filtered or configured, the variant contains
7677
/// that configuration data.
77-
#[derive(Debug, Clone, Eq, PartialEq)]
78+
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
7879
pub enum BundleData {
7980
Reconfigurator,
8081
HostInfo(HashSet<SledSelection>),
@@ -100,7 +101,7 @@ impl BundleData {
100101
/// This wrapper ensures that categories and data always match - you can't
101102
/// insert (BundleDataCategory::Reconfigurator, BundleData::SpDumps)
102103
/// because each BundleData determines its own category.
103-
#[derive(Debug, Clone, Eq, PartialEq)]
104+
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)]
104105
pub struct BundleDataSelection {
105106
data: HashMap<BundleDataCategory, BundleData>,
106107
}
@@ -131,6 +132,11 @@ impl BundleDataSelection {
131132
pub fn get(&self, category: BundleDataCategory) -> Option<&BundleData> {
132133
self.data.get(&category)
133134
}
135+
136+
/// Iterate over all data entries in this selection.
137+
pub fn iter(&self) -> impl Iterator<Item = &BundleData> {
138+
self.data.values()
139+
}
134140
}
135141

136142
impl FromIterator<BundleData> for BundleDataSelection {
@@ -167,7 +173,7 @@ impl Default for BundleDataSelection {
167173
///
168174
/// Multiple values of this enum are joined together into a HashSet.
169175
/// Therefore "SledSelection::All" overrides specific sleds.
170-
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
176+
#[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)]
171177
pub enum SledSelection {
172178
All,
173179
Specific(SledUuid),

0 commit comments

Comments
 (0)