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+ use super :: impl_enum_type;
56use crate :: SpMgsSlot ;
67use crate :: SpType ;
78use crate :: typed_uuid:: DbTypedUuid ;
@@ -12,9 +13,9 @@ use diesel::pg::Pg;
1213use diesel:: prelude:: * ;
1314use diesel:: serialize:: { self , ToSql } ;
1415use diesel:: sql_types;
15- use nexus_db_schema:: schema:: { host_ereport, sp_ereport} ;
16+ use nexus_db_schema:: schema:: { ereport , host_ereport, sp_ereport} ;
1617use nexus_types:: fm:: ereport:: {
17- Ena , Ereport , EreportId , EreportMetadata , Reporter ,
18+ self as fm , Ena , EreportId , EreportMetadata , Reporter ,
1819} ;
1920use omicron_uuid_kinds:: { EreporterRestartKind , OmicronZoneKind , SledKind } ;
2021use serde:: { Deserialize , Serialize } ;
@@ -62,6 +63,133 @@ where
6263 }
6364}
6465
66+ impl_enum_type ! (
67+ EreporterKindEnum :
68+
69+ #[ derive( Clone , Copy , Debug , AsExpression , FromSqlRow , Serialize , Deserialize , PartialEq ) ]
70+ pub enum EreporterKind ;
71+
72+ // Enum values
73+ Sp => b"sp"
74+ Host => b"host"
75+ ) ;
76+
77+ #[ derive( Clone , Debug , Queryable , Selectable ) ]
78+ #[ diesel( table_name = ereport) ]
79+ pub struct Ereport {
80+ pub restart_id : DbTypedUuid < EreporterRestartKind > ,
81+ pub ena : DbEna ,
82+ pub time_collected : DateTime < Utc > ,
83+ pub collector_id : DbTypedUuid < OmicronZoneKind > ,
84+ pub reporter_kind : EreporterKind ,
85+
86+ // The physical location of the reporting SP.
87+ //
88+ /// SP location: the type of SP slot (sled, switch, power shelf).
89+ ///
90+ /// This is always known, as SPs are indexed by physical location when
91+ /// collecting ereports from MGS.
92+ pub sp_type : Option < SpType > ,
93+ /// SP location: the slot number.
94+ ///
95+ /// This is always known, as SPs are indexed by physical location when
96+ /// collecting ereports from MGS.
97+ pub sp_slot : Option < SpMgsSlot > ,
98+ pub sled_id : Option < DbTypedUuid < SledKind > > ,
99+
100+ /// SP VPD identity: the baseboard part number of the reporting SP.
101+ ///
102+ /// This is nullable, as the ereport may have been generated in a condition
103+ /// where the SP was unable to determine its own part number. Consider that
104+ /// "I don't know what I am!" is an error condition for which we might want
105+ /// to generate an ereport!
106+ pub part_number : Option < String > ,
107+ /// SP VPD identity: the baseboard serial number of the reporting SP.
108+ ///
109+ /// This is nullable, as the ereport may have been generated in a condition
110+ /// where the SP was unable to determine its own serial number. Consider that
111+ /// "I don't know who I am!" is an error condition for which we might want
112+ /// to generate an ereport!
113+ pub serial_number : Option < String > ,
114+ /// The ereport class, which indicates the category of event reported.
115+ ///
116+ /// This is nullable, as it is extracted from the report JSON, and reports
117+ /// missing class information must still be ingested.
118+ pub class : Option < String > ,
119+
120+ pub report : serde_json:: Value ,
121+ }
122+
123+ impl TryFrom < Ereport > for fm:: Ereport {
124+ type Error = anyhow:: Error ;
125+ fn try_from ( ereport : Ereport ) -> Result < Self , Self :: Error > {
126+ let reporter = match & ereport {
127+ Ereport {
128+ reporter_kind : EreporterKind :: Sp ,
129+ sp_slot : Some ( slot) ,
130+ sp_type : Some ( sp_type) ,
131+ ..
132+ } => Reporter :: Sp { sp_type : ( * sp_type) . into ( ) , slot : slot. 0 } ,
133+ Ereport {
134+ reporter_kind : EreporterKind :: Sp ,
135+ sp_slot,
136+ sp_type,
137+ ..
138+ } => {
139+ anyhow:: bail!(
140+ "an ereport with reporter_kind='sp' should have a slot \
141+ and sp_type, but found sp_slot={sp_slot:?}, \
142+ sp_type={sp_type:?}",
143+ ) ;
144+ }
145+ Ereport {
146+ reporter_kind : EreporterKind :: Host ,
147+ sled_id : Some ( sled_id) ,
148+ ..
149+ } => Reporter :: HostOs { sled : ( * sled_id) . into ( ) } ,
150+ Ereport {
151+ reporter_kind : EreporterKind :: Host ,
152+ sled_id : None ,
153+ ..
154+ } => {
155+ anyhow:: bail!(
156+ "an ereport with reporter_kind='host' should have a \
157+ non-null sled UUID"
158+ ) ;
159+ }
160+ } ;
161+
162+ let Ereport {
163+ restart_id,
164+ ena,
165+ reporter_kind : _,
166+ time_collected,
167+ collector_id,
168+ part_number,
169+ serial_number,
170+ sp_type : _,
171+ sp_slot : _,
172+ sled_id : _,
173+ class,
174+ report,
175+ } = ereport;
176+ Ok ( fm:: Ereport {
177+ id : EreportId { restart_id : restart_id. into ( ) , ena : ena. into ( ) } ,
178+ part_number,
179+ serial_number,
180+ class,
181+ metadata : EreportMetadata {
182+ time_collected,
183+ // The `ereport` view only contains ereports which haven't been deleted
184+ time_deleted : None ,
185+ collector_id : collector_id. into ( ) ,
186+ } ,
187+ reporter,
188+ report,
189+ } )
190+ }
191+ }
192+
65193#[ derive( Clone , Debug , Insertable , Queryable , Selectable ) ]
66194#[ diesel( table_name = sp_ereport) ]
67195pub struct SpEreport {
@@ -109,7 +237,7 @@ pub struct SpEreport {
109237 pub report : serde_json:: Value ,
110238}
111239
112- impl From < SpEreport > for Ereport {
240+ impl From < SpEreport > for fm :: Ereport {
113241 fn from ( sp_report : SpEreport ) -> Self {
114242 let SpEreport {
115243 restart_id,
@@ -124,7 +252,7 @@ impl From<SpEreport> for Ereport {
124252 class,
125253 report,
126254 } = sp_report;
127- Ereport {
255+ fm :: Ereport {
128256 id : EreportId { restart_id : restart_id. into ( ) , ena : ena. into ( ) } ,
129257 part_number,
130258 serial_number,
@@ -167,7 +295,7 @@ pub struct HostEreport {
167295 pub part_number : Option < String > ,
168296}
169297
170- impl From < HostEreport > for Ereport {
298+ impl From < HostEreport > for fm :: Ereport {
171299 fn from ( host_report : HostEreport ) -> Self {
172300 let HostEreport {
173301 restart_id,
@@ -181,8 +309,11 @@ impl From<HostEreport> for Ereport {
181309 report,
182310 part_number,
183311 } = host_report;
184- Ereport {
185- id : EreportId { restart_id : restart_id. into ( ) , ena : ena. into ( ) } ,
312+ fm:: Ereport {
313+ id : fm:: EreportId {
314+ restart_id : restart_id. into ( ) ,
315+ ena : ena. into ( ) ,
316+ } ,
186317 part_number,
187318 serial_number : Some ( sled_serial) ,
188319 class,
0 commit comments