Skip to content
Open
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
3 changes: 2 additions & 1 deletion dev-tools/omdb/src/bin/omdb/db/alert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,7 @@ async fn cmd_db_alert_info(
payload,
num_dispatched,
case_id,
version,
} = alert;

const CLASS: &str = "class";
Expand All @@ -1050,7 +1051,7 @@ async fn cmd_db_alert_info(

println!("\n{:=<80}", "== ALERT ");
println!(" {ID:>WIDTH$}: {id:?}");
println!(" {CLASS:>WIDTH$}: {class}");
println!(" {CLASS:>WIDTH$}: {class}, v{}", u32::from(version));
println!(" {TIME_CREATED:>WIDTH$}: {time_created}");
println!(" {TIME_MODIFIED:>WIDTH$}: {time_modified}");
println!();
Expand Down
53 changes: 43 additions & 10 deletions nexus/db-model/src/alert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@

use crate::AlertClass;
use crate::DbTypedUuid;
use crate::SqlU32;
use chrono::{DateTime, Utc};
use db_macros::Asset;
use nexus_db_schema::schema::alert;
use nexus_types::alert::AlertPayload;
use nexus_types::fm::case;
use omicron_common::api::external::Error;
use omicron_uuid_kinds::AlertUuid;
use omicron_uuid_kinds::CaseKind;
use omicron_uuid_kinds::CaseUuid;
Expand Down Expand Up @@ -48,37 +51,62 @@ pub struct Alert {

/// The ID of the fault management case that created this alert, if any.
pub case_id: Option<DbTypedUuid<CaseKind>>,

/// The version of the alert class' schema that this alert's payload
/// conforms to.
#[diesel(column_name = alert_version)]
pub version: SqlU32,
}

impl Alert {
/// UUID of the singleton event entry for alert receiver liveness probes.
pub const PROBE_ALERT_ID: uuid::Uuid =
uuid::Uuid::from_u128(0x001de000_7768_4000_8000_000000000001);

/// Returns an `Alert` model representing a newly-created alert, with the
/// provided ID, alert class, and JSON payload.
pub fn new(
/// Returns an `Alert` model representing a newly-created alert with the
/// provided ID.
///
/// The alert's class and schema version are taken from the [`AlertPayload`]
/// trait implementation of the provided `alert` value, and the value itself
/// is serialized to form the alert's JSON data payload.
pub fn new<A: AlertPayload>(
id: impl Into<AlertUuid>,
class: impl Into<AlertClass>,
payload: impl Into<serde_json::Value>,
) -> Self {
Self {
alert: &A,
) -> Result<Self, Error> {
let class = A::CLASS;
let version = A::VERSION;
let payload =
serde_json::to_value(alert).map_err(|e| Error::InternalError {
internal_message: format!(
"failed to serialize {class} v{version} alert payload \
(Rust type {}): {e}",
std::any::type_name::<A>(),
),
})?;
Ok(Self {
identity: AlertIdentity::new(id.into()),
time_dispatched: None,
class: class.into(),
payload: payload.into(),
version: SqlU32::new(version),
payload,
num_dispatched: 0,
case_id: None,
}
})
}

/// Returns an `Alert` model representing the alert requested by a fault
/// management alert request.
///
/// The alert's class, version, and payload are determined from the provided
/// alert request record.
pub fn for_fm_alert_request(
req: &case::AlertRequest,
case_id: CaseUuid,
) -> Self {
let &case::AlertRequest {
id,
class,
version,
ref payload,
// Ignore the sitrep ID and comment fields, as they are not
// included in the alert model.
Expand All @@ -87,8 +115,13 @@ impl Alert {
} = req;

Self {
identity: AlertIdentity::new(id),
time_dispatched: None,
class: class.into(),
version: SqlU32::new(version),
payload: payload.clone(),
num_dispatched: 0,
case_id: Some(case_id.into()),
..Self::new(id, class, payload.clone())
}
}
}
8 changes: 8 additions & 0 deletions nexus/db-model/src/fm/alert_request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

use crate::AlertClass;
use crate::DbTypedUuid;
use crate::SqlU32;
use nexus_db_schema::schema::fm_alert_request;
use nexus_types::fm;
use omicron_uuid_kinds::{AlertKind, CaseKind, SitrepKind};
Expand All @@ -29,6 +30,10 @@ pub struct AlertRequest {
/// emit a different comment string for an analogous determination across
/// different software versions.
pub comment: String,
/// The version of the alert class' schema that this alert's payload
/// conforms to.
#[diesel(column_name = "alert_version")]
pub version: SqlU32,
}

impl AlertRequest {
Expand All @@ -42,6 +47,7 @@ impl AlertRequest {
requested_sitrep_id,
payload,
class,
version,
comment,
} = req;
AlertRequest {
Expand All @@ -50,6 +56,7 @@ impl AlertRequest {
requested_sitrep_id: requested_sitrep_id.into(),
case_id: case_id.into(),
class: class.into(),
version: SqlU32::new(version),
payload,
comment,
}
Expand All @@ -63,6 +70,7 @@ impl From<AlertRequest> for fm::case::AlertRequest {
requested_sitrep_id: req.requested_sitrep_id.into(),
payload: req.payload,
class: req.class.into(),
version: u32::from(req.version),
comment: req.comment,
}
}
Expand Down
3 changes: 2 additions & 1 deletion nexus/db-model/src/schema_versions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use std::{collections::BTreeMap, sync::LazyLock};
///
/// This must be updated when you change the database schema. Refer to
/// schema/crdb/README.adoc in the root of this repository for details.
pub const SCHEMA_VERSION: Version = Version::new(263, 0, 0);
pub const SCHEMA_VERSION: Version = Version::new(264, 0, 0);

/// List of all past database schema versions, in *reverse* order
///
Expand All @@ -28,6 +28,7 @@ pub static KNOWN_VERSIONS: LazyLock<Vec<KnownVersion>> = LazyLock::new(|| {
// | leaving the first copy as an example for the next person.
// v
// KnownVersion::new(next_int, "unique-dirname-with-the-sql-files"),
KnownVersion::new(264, "alert-version"),
KnownVersion::new(263, "external-jumbo-frames"),
KnownVersion::new(262, "rename-ip-pool-reservation-type"),
KnownVersion::new(261, "remove-add-zones-with-mupdate-override"),
Expand Down
31 changes: 22 additions & 9 deletions nexus/db-queries/src/db/datastore/alert_rx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,7 @@ mod test {
use crate::db::model::Alert;
use crate::db::pub_test_utils::TestDatabase;
use nexus_db_lookup::LookupPath;
use nexus_types::alert::test_alerts;
use omicron_common::api::external::IdentityMetadataCreateParams;
use omicron_test_utils::dev;
use omicron_uuid_kinds::AlertUuid;
Expand Down Expand Up @@ -1201,16 +1202,16 @@ mod test {
.expect("cant create ye webhook receiver!!!!")
}

async fn create_alert(
async fn create_alert<A: nexus_types::alert::AlertPayload>(
datastore: &DataStore,
opctx: &OpContext,
alert_class: AlertClass,
alert: &A,
) -> (authz::Alert, Alert) {
let id = AlertUuid::new_v4();
datastore
.alert_create(
opctx,
Alert::new(id, alert_class, serde_json::json!({})),
Alert::new(id, alert).expect("alert payload should serialize"),
)
.await
.expect("cant create ye event");
Expand Down Expand Up @@ -1455,12 +1456,24 @@ mod test {
.await
.expect("cant get ye receiver");

let (authz_foo, _) =
create_alert(datastore, opctx, AlertClass::TestFoo).await;
let (authz_foo_bar, _) =
create_alert(datastore, opctx, AlertClass::TestFooBar).await;
let (authz_quux_bar, _) =
create_alert(datastore, opctx, AlertClass::TestQuuxBar).await;
let (authz_foo, _) = create_alert(
datastore,
opctx,
&test_alerts::Foo(serde_json::json!({})),
)
.await;
let (authz_foo_bar, _) = create_alert(
datastore,
opctx,
&test_alerts::FooBar(serde_json::json!({})),
)
.await;
let (authz_quux_bar, _) = create_alert(
datastore,
opctx,
&test_alerts::QuuxBar(serde_json::json!({})),
)
.await;

let is_subscribed_foo = datastore
.alert_rx_is_subscribed_to_alert(opctx, &authz_rx, &authz_foo)
Expand Down
4 changes: 4 additions & 0 deletions nexus/db-queries/src/db/datastore/fm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2188,6 +2188,7 @@ mod tests {
.insert_unique(fm::case::AlertRequest {
id: AlertUuid::new_v4(),
class: AlertClass::TestFoo,
version: 0,
payload: serde_json::json!({}),
requested_sitrep_id: sitrep_id,
comment: String::new(),
Expand All @@ -2197,6 +2198,7 @@ mod tests {
.insert_unique(fm::case::AlertRequest {
id: AlertUuid::new_v4(),
class: AlertClass::TestFooBar,
version: 0,
payload: serde_json::json!({}),
requested_sitrep_id: sitrep_id,
comment: String::new(),
Expand Down Expand Up @@ -2271,6 +2273,7 @@ mod tests {
.insert_unique(fm::case::AlertRequest {
id: AlertUuid::new_v4(),
class: AlertClass::TestQuuxBar,
version: 0,
payload: serde_json::json!({}),
requested_sitrep_id: sitrep_id,
comment: String::new(),
Expand Down Expand Up @@ -2800,6 +2803,7 @@ mod tests {
requested_sitrep_id: ghost_sitrep_id.into(),
case_id: ghost_case_id.into(),
class: AlertClass::Probe.into(),
version: 0u32.into(),
payload: serde_json::json!({}),
comment: String::new(),
})
Expand Down
23 changes: 16 additions & 7 deletions nexus/db-queries/src/db/datastore/webhook_delivery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use crate::db::model::Alert;
use crate::db::model::AlertClass;
use crate::db::model::AlertDeliveryState;
use crate::db::model::AlertDeliveryTrigger;
use crate::db::model::SqlU32;
use crate::db::model::WebhookDelivery;
use crate::db::model::WebhookDeliveryAttempt;
use crate::db::model::WebhookDeliveryAttemptResult;
Expand Down Expand Up @@ -58,6 +59,7 @@ pub struct DeliveryConfig {
pub struct DeliveryAndEvent {
pub delivery: WebhookDelivery,
pub alert_class: AlertClass,
pub alert_version: SqlU32,
pub event: serde_json::Value,
}

Expand Down Expand Up @@ -240,14 +242,20 @@ impl DataStore {
.select((
WebhookDelivery::as_select(),
alert_dsl::alert_class,
alert_dsl::alert_version,
alert_dsl::payload,
))
.load_async(&*conn)
.await
.map_err(|e| public_error_from_diesel(e, ErrorHandler::Server))?;
Ok(rows.into_iter().map(|(delivery, alert_class, event)| {
DeliveryAndEvent { delivery, alert_class, event }
}))
Ok(rows.into_iter().map(
|(delivery, alert_class, alert_version, event)| DeliveryAndEvent {
delivery,
alert_class,
alert_version,
event,
},
))
}

pub async fn webhook_delivery_start_attempt(
Expand Down Expand Up @@ -452,6 +460,7 @@ mod test {
use crate::db::pagination::Paginator;
use crate::db::pub_test_utils::TestDatabase;
use crate::db::raw_query_builder::expectorate_query_contents;
use nexus_types::alert::test_alerts;
use nexus_types::external_api::alert;
use omicron_common::api::external::IdentityMetadataCreateParams;
use omicron_test_utils::dev;
Expand Down Expand Up @@ -488,11 +497,11 @@ mod test {
let alert_id = AlertUuid::new_v4();
let alert = model::Alert::new(
alert_id,
model::AlertClass::TestFoo,
serde_json::json!({
&test_alerts::Foo(serde_json::json!({
"answer": 42,
}),
);
})),
)
.expect("alert payload should serialize");
datastore
.alert_create(&opctx, alert)
.await
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ SELECT
alert.alert_class,
alert.payload,
alert.num_dispatched,
alert.case_id
alert.case_id,
alert.alert_version
FROM
alert INNER JOIN webhook_delivery AS delivery ON delivery.alert_id = alert.id
WHERE
Expand Down
2 changes: 2 additions & 0 deletions nexus/db-schema/src/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2902,6 +2902,7 @@ table! {
time_dispatched -> Nullable<Timestamptz>,
num_dispatched -> Int8,
case_id -> Nullable<Uuid>,
alert_version -> Int8,
}
}

Expand Down Expand Up @@ -3276,6 +3277,7 @@ table! {
alert_class -> crate::enums::AlertClassEnum,
payload -> Jsonb,
comment -> Text,
alert_version -> Int8,
}
}

Expand Down
4 changes: 2 additions & 2 deletions nexus/fm/src/analysis_input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ mod tests {
use super::*;
use crate::builder::SitrepBuilder;
use crate::test_util::FmTest;
use nexus_types::alert::test_alerts;
use nexus_types::fm;
use nexus_types::fm::case::CaseEreport;
use nexus_types::fm::ereport::Reporter;
Expand Down Expand Up @@ -588,8 +589,7 @@ mod tests {
);
new_case
.request_alert(
nexus_types::alert::AlertClass::TestFooBar,
&serde_json::json!({"alert": true}),
&test_alerts::FooBar(serde_json::json!({"alert": true})),
"requesting an alert to tell someone about something",
)
.unwrap();
Expand Down
Loading
Loading