Skip to content

Commit e951689

Browse files
committed
commentary + a few API tweaks
1 parent c158789 commit e951689

File tree

5 files changed

+101
-29
lines changed

5 files changed

+101
-29
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,7 @@ async fn cmd_db_sitrep_show(
290290
),
291291
Some(fm::SitrepVersion { version, time_made_current, .. }) => {
292292
let current_version =
293-
datastore.fm_get_current_sitrep_version(&opctx).await;
293+
datastore.fm_current_sitrep_version(&opctx).await;
294294
if matches!(current_version, Ok(Some(ref v)) if v.id == id) {
295295
println!(" {STATUS:>WIDTH$}: this is the current sitrep!",);
296296
} else {

nexus/db-model/src/fm_sitrep.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,16 @@
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-
//! Types for representing fault management sitreps in the database.
5+
//! Types for representing fault management situation reports (sitreps) in the
6+
//! database.
7+
//!
8+
//! The fault management sitrep, and the ways in which it is represented in
9+
//! CRDB, is described in detail in [RFD
10+
//! 603](https://rfd.shared.oxide.computer/rfd/0603).
11+
//!
12+
//! These types are used when inserting and reading sitreps in CRDB; when in
13+
//! use, the sitrep is represented as a [`nexus_types::fm::Sitrep`]. See the
14+
//! documentation in [`nexus_types::fm`] for more information.
615
716
use crate::SqlU32;
817
use crate::typed_uuid::DbTypedUuid;

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

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,23 @@ use omicron_uuid_kinds::SitrepUuid;
3434
use uuid::Uuid;
3535

3636
impl DataStore {
37-
pub async fn fm_get_current_sitrep_version(
37+
/// Reads the current [sitrep version](fm::SitrepVersion) from CRDB.
38+
///
39+
/// If no sitreps have been generated, this returns `None`.
40+
pub async fn fm_current_sitrep_version(
3841
&self,
3942
opctx: &OpContext,
4043
) -> Result<Option<fm::SitrepVersion>, Error> {
4144
opctx.authorize(authz::Action::ListChildren, &authz::FLEET).await?;
4245
let conn = self.pool_connection_authorized(opctx).await?;
4346
let version = self
44-
.fm_get_current_sitrep_version_on_conn(&conn)
47+
.fm_current_sitrep_version_on_conn(&conn)
4548
.await?
4649
.map(Into::into);
4750
Ok(version)
4851
}
4952

50-
async fn fm_get_current_sitrep_version_on_conn(
53+
async fn fm_current_sitrep_version_on_conn(
5154
&self,
5255
conn: &async_bb8_diesel::Connection<DbConnection>,
5356
) -> Result<Option<model::SitrepVersion>, Error> {
@@ -60,48 +63,60 @@ impl DataStore {
6063
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
6164
}
6265

66+
/// Reads the [`fm::SitrepMetadata`] describing the sitrep with the given
67+
/// ID, if one exists.
6368
pub async fn fm_sitrep_metadata_read(
6469
&self,
6570
opctx: &OpContext,
6671
id: SitrepUuid,
67-
) -> Result<Option<fm::SitrepMetadata>, Error> {
72+
) -> Result<fm::SitrepMetadata, Error> {
6873
opctx.authorize(authz::Action::ListChildren, &authz::FLEET).await?;
6974
let conn = self.pool_connection_authorized(opctx).await?;
70-
let meta = self
71-
.fm_sitrep_metadata_read_on_conn(id, &conn)
72-
.await?
73-
.map(Into::into);
75+
let meta =
76+
self.fm_sitrep_metadata_read_on_conn(id, &conn).await?.into();
7477
Ok(meta)
7578
}
7679

7780
async fn fm_sitrep_metadata_read_on_conn(
7881
&self,
7982
id: SitrepUuid,
8083
conn: &async_bb8_diesel::Connection<DbConnection>,
81-
) -> Result<Option<model::SitrepMetadata>, Error> {
84+
) -> Result<model::SitrepMetadata, Error> {
8285
sitrep_dsl::fm_sitrep
8386
.filter(sitrep_dsl::id.eq(id.into_untyped_uuid()))
8487
.select(model::SitrepMetadata::as_select())
8588
.first_async(conn)
8689
.await
8790
.optional()
88-
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))
91+
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?
92+
.ok_or_else(|| {
93+
Error::non_resourcetype_not_found(format!("sitrep {id:?}"))
94+
})
8995
}
9096

97+
/// Reads the *entire* current sitrep, along with its version.
98+
///
99+
/// This is equivalent to reading the current sitrep version using
100+
/// [`DataStore::fm_current_sitrep_version`], and then reading the sitrep
101+
/// itself using [`DataStore::fm_sitrep_read_on_conn`].
102+
///
103+
/// If this method returns `None`, there is no current sitrep, meaning that
104+
/// no sitreps have been created.
91105
pub async fn fm_sitrep_read_current(
92106
&self,
93107
opctx: &OpContext,
94-
) -> Result<Option<(fm::SitrepVersion, fm::Sitrep)>, Error> {
108+
) -> Result<Option<(fm::SitrepVersion, Sitrep)>, Error> {
95109
let conn = self.pool_connection_authorized(opctx).await?;
96110
let version: fm::SitrepVersion =
97-
match self.fm_get_current_sitrep_version_on_conn(&conn).await? {
111+
match self.fm_current_sitrep_version_on_conn(&conn).await? {
98112
Some(version) => version.into(),
99113
None => return Ok(None),
100114
};
101115
let sitrep = self.fm_sitrep_read_on_conn(version.id, &conn).await?;
102116
Ok(Some((version, sitrep)))
103117
}
104118

119+
/// Reads the entire content of the sitrep with the provided ID, if one exists.
105120
pub async fn fm_sitrep_read(
106121
&self,
107122
opctx: &OpContext,
@@ -117,13 +132,8 @@ impl DataStore {
117132
id: SitrepUuid,
118133
conn: &async_bb8_diesel::Connection<DbConnection>,
119134
) -> Result<Sitrep, Error> {
120-
let metadata = self
121-
.fm_sitrep_metadata_read_on_conn(id, &conn)
122-
.await?
123-
.ok_or_else(|| {
124-
Error::non_resourcetype_not_found(format!("sitrep {id:?}"))
125-
})?
126-
.into();
135+
let metadata =
136+
self.fm_sitrep_metadata_read_on_conn(id, &conn).await?.into();
127137

128138
// TODO(eliza): this is where we would read all the other sitrep data,
129139
// if there was any.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ impl SitrepLoader {
8181
let time_loaded = Utc::now();
8282
let current_version: SitrepVersion = match self
8383
.datastore
84-
.fm_get_current_sitrep_version(opctx)
84+
.fm_current_sitrep_version(opctx)
8585
.await
8686
{
8787
Ok(Some(version)) => version.into(),

nexus/types/src/fm.rs

Lines changed: 60 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,34 @@
33
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
44

55
//! Fault management types.
6+
//!
7+
//! Of particular importance is the [`Sitrep`], which is the top-level data
8+
//! structure containing fault management state.
69
710
use chrono::{DateTime, Utc};
811
use omicron_uuid_kinds::{CollectionUuid, OmicronZoneUuid, SitrepUuid};
912
use schemars::JsonSchema;
1013
use serde::{Deserialize, Serialize};
1114

15+
/// A fault management situation report, or _sitrep_.
16+
///
17+
/// The sitrep is a data structure that represents a snapshot of the state of
18+
/// the system as understood by the control plane's fault management subsystem.
19+
/// At any point in time, a single sitrep is considered the "current" sitrep.
20+
/// Each sitrep records a _parent sitrep ID_, which indicates the sitrep that
21+
/// was current at the time that the sitrep was created.
22+
/// A sitrep may only be made current if its parent is the current sitrep.
23+
/// This ensures that there is a sequentially consistent history of sitreps.
24+
/// The fault management subsystem only considers data from the current sitrep
25+
/// when making decisions and diagnoses.
26+
///
27+
/// The sitrep, how it is represented in the database, and how the fault
28+
/// management subsystem creates and interacts with sitreps, is described in
29+
/// detail in [RFD 603](https://rfd.shared.oxide.computer/rfd/0603).
1230
#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
1331
pub struct Sitrep {
32+
/// Metadata describing this sitrep, when it was created, its parent sitrep
33+
/// ID, and which Nexus produced it.
1434
pub metadata: SitrepMetadata,
1535
// TODO(eliza): draw the rest of the sitrep
1636
}
@@ -25,19 +45,52 @@ impl Sitrep {
2545
}
2646
}
2747

28-
#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
29-
pub struct SitrepVersion {
30-
pub id: SitrepUuid,
31-
pub version: u32,
32-
pub time_made_current: DateTime<Utc>,
33-
}
34-
48+
/// Metadata describing a sitrep.
49+
///
50+
/// This corresponds to the records stored in the `fm_sitrep` database table.
3551
#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
3652
pub struct SitrepMetadata {
53+
/// The ID of this sitrep.
3754
pub id: SitrepUuid,
55+
56+
/// The ID of the parent sitrep.
57+
///
58+
/// A sitrep's _parent_ is the sitrep that was current when the planning
59+
/// phase that produced that sitrep ran. The parent sitrep is a planning
60+
/// input that produced this sitrep.
61+
///
62+
/// The parent sitrep ID is optional, because this sitrep _may_ be the first
63+
/// sitrep ever generated by the system. However, once a current sitrep has
64+
/// been set, no subsequent sitrep should be created without a parent.
3865
pub parent_sitrep_id: Option<SitrepUuid>,
66+
67+
/// The ID of the inventory collection that was used as planning input to
68+
/// this sitrep.
69+
///
70+
/// When generating a new sitrep, the fault manager should ensure that the
71+
/// inventory collection it uses as input is at least as new as the parent
72+
/// sitrep's inventory collection.
3973
pub inv_collection_id: CollectionUuid,
74+
75+
/// The Omicron zone UUID of the Nexus that generated this sitrep.
76+
///
77+
/// This is intended for debugging purposes.
4078
pub creator_id: OmicronZoneUuid,
79+
80+
/// A human-readable (but mechanically generated) string describing the
81+
/// reason(s) this sitrep was created.
82+
///
83+
/// This is intended for debugging purposes.
4184
pub comment: String,
85+
86+
/// The time at which this sitrep was created.
4287
pub time_created: DateTime<Utc>,
4388
}
89+
90+
/// An entry in the sitrep version history.
91+
#[derive(Clone, Debug, Eq, PartialEq, JsonSchema, Deserialize, Serialize)]
92+
pub struct SitrepVersion {
93+
pub id: SitrepUuid,
94+
pub version: u32,
95+
pub time_made_current: DateTime<Utc>,
96+
}

0 commit comments

Comments
 (0)