Skip to content

Commit 8ea8e50

Browse files
committed
start throwing together some kind of DE stuff
1 parent ff04227 commit 8ea8e50

File tree

11 files changed

+192
-18
lines changed

11 files changed

+192
-18
lines changed

Cargo.lock

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

dev-tools/omdb/src/bin/omdb/db/sitrep.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ async fn cmd_db_sitrep_show(
249249
}
250250
};
251251

252-
let fm::Sitrep { metadata } = sitrep;
252+
let fm::Sitrep { metadata, cases, alerts_requested } = sitrep;
253253
let fm::SitrepMetadata {
254254
id,
255255
creator_id,

ereport/types/src/lib.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -102,7 +102,9 @@ impl TryFrom<i64> for Ena {
102102
}
103103

104104
/// Unique identifier for an ereport.
105-
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
105+
#[derive(
106+
Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord,
107+
)]
106108
pub struct EreportId {
107109
pub restart_id: EreporterRestartUuid,
108110
pub ena: Ena,

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,12 @@ impl DataStore {
143143
// TODO(eliza): this is where we would read all the other sitrep data,
144144
// if there was any.
145145

146-
Ok(Sitrep { metadata })
146+
Ok(Sitrep {
147+
metadata,
148+
// TODO(eliza) read these
149+
alerts_requested: Default::default(),
150+
cases: Default::default(),
151+
})
147152
}
148153

149154
/// Insert the provided [`Sitrep`] into the database, and attempt to mark it

nexus/fm/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ edition = "2021"
77
workspace = true
88

99
[dependencies]
10-
nexus-types.workspace = true
10+
anyhow.workspace = true
1111
chrono.workspace = true
12+
iddqd.workspace = true
13+
nexus-types.workspace = true
1214
omicron-uuid-kinds.workspace = true
15+
slog.workspace = true
1316

1417
omicron-workspace-hack.workspace = true

nexus/fm/src/de.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! Diagnosis engines
6+
7+
pub mod power_shelf;

nexus/fm/src/de/power_shelf.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
//! Power shelf diagnosis
6+
use crate::SitrepBuilder;
7+
8+
pub fn diagnose(sitrep: &mut SitrepBuilder<'_>) -> anyhow::Result<()> {
9+
Ok(())
10+
}

nexus/fm/src/lib.rs

Lines changed: 86 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,37 +6,116 @@
66
77
use nexus_types::fm;
88
use nexus_types::inventory;
9+
use omicron_uuid_kinds::CaseUuid;
910
use omicron_uuid_kinds::OmicronZoneUuid;
1011
use omicron_uuid_kinds::SitrepUuid;
12+
use slog::Logger;
13+
use std::fmt::Write;
14+
15+
pub mod de;
1116

1217
#[derive(Debug)]
1318
pub struct SitrepBuilder<'a> {
14-
inventory: &'a inventory::Collection,
15-
parent_sitrep: Option<&'a fm::Sitrep>,
19+
pub log: Logger,
20+
pub inventory: &'a inventory::Collection,
21+
pub parent_sitrep: Option<&'a fm::Sitrep>,
22+
pub sitrep_id: SitrepUuid,
23+
pub cases: iddqd::IdOrdMap<fm::Case>,
1624
comment: String,
1725
}
1826

1927
impl<'a> SitrepBuilder<'a> {
2028
pub fn new(
29+
log: &Logger,
2130
inventory: &'a inventory::Collection,
2231
parent_sitrep: Option<&'a fm::Sitrep>,
2332
) -> Self {
24-
SitrepBuilder { inventory, parent_sitrep, comment: String::new() }
33+
let sitrep_id = SitrepUuid::new_v4();
34+
let log = log.new(slog::o!(
35+
"sitrep_id" => format!("{sitrep_id:?}"),
36+
"parent_sitrep_id" => format!("{:?}", parent_sitrep.as_ref().map(|s| s.id())),
37+
"inv_collection_id" => format!("{:?}", inventory.id),
38+
));
39+
SitrepBuilder {
40+
log,
41+
sitrep_id,
42+
inventory,
43+
parent_sitrep,
44+
comment: String::new(),
45+
cases: Default::default(),
46+
}
47+
}
48+
49+
pub fn open_case(&mut self, case: fm::Case) -> anyhow::Result<CaseUuid> {
50+
let case_id = case.id;
51+
if self.cases.contains_key(&case_id) {
52+
anyhow::bail!("case with ID {case_id:?} already exists");
53+
}
54+
55+
slog::info!(
56+
self.log,
57+
"opened case {case_id:?}";
58+
"case_id" => ?case_id,
59+
"de" => %case.de
60+
);
61+
62+
writeln!(&mut self.comment, "* de {} opened case {case_id:?}", case.de)
63+
.unwrap();
64+
65+
self.cases
66+
.insert_unique(case)
67+
.expect("we just checked that it doesn't exist");
68+
Ok(case_id)
69+
}
70+
71+
pub fn request_alert(
72+
&mut self,
73+
case_id: CaseUuid,
74+
req: fm::AlertRequest,
75+
) -> anyhow::Result<()> {
76+
let mut case = self.cases
77+
.get_mut(&case_id)
78+
.ok_or_else(|| anyhow::anyhow!(
79+
"cannot create an alert request for non-existent case ID {case_id:?}",
80+
))?;
81+
let alert_id = req.id;
82+
let alert_class = req.class;
83+
84+
case.alerts_requested.insert_unique(req).map_err(|_| {
85+
anyhow::anyhow!("an alert with ID {alert_id:?} already exists")
86+
})?;
87+
88+
writeln!(
89+
&mut self.comment,
90+
"* de {} requested {alert_class:?} alert {alert_id:?} for case \
91+
{case_id:?}",
92+
case.de
93+
)
94+
.unwrap();
95+
96+
slog::info!(
97+
self.log,
98+
"requested an alert for case {case_id:?}";
99+
"case_id" => ?case_id,
100+
"de" => %case.de,
101+
"alert_id" => ?alert_id,
102+
"alert_class" => ?alert_class,
103+
);
104+
105+
Ok(())
25106
}
26-
27-
28107

29108
pub fn build(self, creator_id: OmicronZoneUuid) -> fm::Sitrep {
30109
fm::Sitrep {
31110
metadata: fm::SitrepMetadata {
32-
id: SitrepUuid::new_v4(),
111+
id: self.sitrep_id,
33112
parent_sitrep_id: self.parent_sitrep.map(|s| s.metadata.id),
34113
inv_collection_id: self.inventory.id,
35114
creator_id,
36115
comment: self.comment,
37116
time_created: chrono::Utc::now(),
38117
},
39-
// TODO(eliza): draw the rest of the owl...
118+
cases: self.cases,
40119
}
41120
}
42121
}

nexus/types/src/fm.rs

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,19 @@
88
//! structure containing fault management state.
99
1010
use chrono::{DateTime, Utc};
11-
use omicron_uuid_kinds::{CollectionUuid, OmicronZoneUuid, SitrepUuid};
12-
use schemars::JsonSchema;
11+
use iddqd::{IdOrdItem, IdOrdMap};
12+
use omicron_uuid_kinds::{
13+
CaseUuid, CollectionUuid, OmicronZoneUuid, SitrepUuid,
14+
};
1315
use serde::{Deserialize, Serialize};
16+
use std::collections::BTreeSet;
1417

15-
pub use ereport::Ereport;
18+
pub use ereport::{Ereport, EreportId};
1619
pub mod ereport;
1720

21+
mod alert;
22+
pub use alert::*;
23+
1824
/// A fault management situation report, or _sitrep_.
1925
///
2026
/// The sitrep is a data structure that represents a snapshot of the state of
@@ -30,12 +36,12 @@ pub mod ereport;
3036
/// The sitrep, how it is represented in the database, and how the fault
3137
/// management subsystem creates and interacts with sitreps, is described in
3238
/// detail in [RFD 603](https://rfd.shared.oxide.computer/rfd/0603).
33-
#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
39+
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
3440
pub struct Sitrep {
3541
/// Metadata describing this sitrep, when it was created, its parent sitrep
3642
/// ID, and which Nexus produced it.
3743
pub metadata: SitrepMetadata,
38-
// TODO(eliza): draw the rest of the sitrep
44+
pub cases: IdOrdMap<Case>,
3945
}
4046

4147
impl Sitrep {
@@ -46,12 +52,22 @@ impl Sitrep {
4652
pub fn parent_id(&self) -> Option<SitrepUuid> {
4753
self.metadata.parent_sitrep_id
4854
}
55+
56+
/// Iterate over all alerts requested by cases in this sitrep.
57+
pub fn alerts_requested(
58+
&self,
59+
) -> impl Iterator<Item = (CaseUuid, &'_ AlertRequest)> + '_ {
60+
self.cases.iter().flat_map(|case| {
61+
let case_id = case.id;
62+
case.alerts_requested.iter().map(move |alert| (case_id, alert))
63+
})
64+
}
4965
}
5066

5167
/// Metadata describing a sitrep.
5268
///
5369
/// This corresponds to the records stored in the `fm_sitrep` database table.
54-
#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
70+
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
5571
pub struct SitrepMetadata {
5672
/// The ID of this sitrep.
5773
pub id: SitrepUuid,
@@ -91,9 +107,28 @@ pub struct SitrepMetadata {
91107
}
92108

93109
/// An entry in the sitrep version history.
94-
#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
110+
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
95111
pub struct SitrepVersion {
96112
pub id: SitrepUuid,
97113
pub version: u32,
98114
pub time_made_current: DateTime<Utc>,
99115
}
116+
117+
#[derive(Clone, Debug, Eq, PartialEq, Deserialize, Serialize)]
118+
pub struct Case {
119+
pub id: CaseUuid,
120+
pub created_sitrep_id: SitrepUuid,
121+
pub de: String,
122+
pub ereports: BTreeSet<EreportId>,
123+
// TODO(eliza) what else?
124+
pub alerts_requested: IdOrdMap<AlertRequest>, // TODO(eliza): draw the rest of the sitrep
125+
}
126+
127+
impl IdOrdItem for Case {
128+
type Key<'a> = &'a CaseUuid;
129+
fn key(&self) -> Self::Key<'_> {
130+
&self.id
131+
}
132+
133+
iddqd::id_upcast!();
134+
}

nexus/types/src/fm/alert.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// This Source Code Form is subject to the terms of the Mozilla Public
2+
// License, v. 2.0. If a copy of the MPL was not distributed with this
3+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
4+
5+
use omicron_uuid_kinds::AlertUuid;
6+
use omicron_uuid_kinds::SitrepUuid;
7+
use serde::{Deserialize, Serialize};
8+
9+
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
10+
pub struct AlertRequest {
11+
pub id: AlertUuid,
12+
pub class: AlertClass,
13+
pub payload: serde_json::Value,
14+
pub requested_sitrep_id: SitrepUuid,
15+
}
16+
17+
impl iddqd::IdOrdItem for AlertRequest {
18+
type Key<'a> = &'a AlertUuid;
19+
fn key(&self) -> Self::Key<'_> {
20+
&self.id
21+
}
22+
23+
iddqd::id_upcast!();
24+
}
25+
26+
#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
27+
pub enum AlertClass {
28+
// TODO
29+
}

0 commit comments

Comments
 (0)