Skip to content

Commit 9d1bd55

Browse files
authored
[MGS] Flesh out SpState information (#2287)
Adds serial number/model/revision, hubris image information, and RoT information.
1 parent b062e95 commit 9d1bd55

File tree

15 files changed

+607
-112
lines changed

15 files changed

+607
-112
lines changed

Cargo.lock

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

gateway-client/src/lib.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ progenitor::generate_api!(
4747
slog::debug!(log, "client response"; "result" => ?result);
4848
}),
4949
derives = [schemars::JsonSchema],
50-
patch =
51-
{ SpIdentifier = { derives = [Copy, PartialEq, Eq, PartialOrd, Ord] },
52-
SpState = { derives = [ PartialEq, Eq, PartialOrd, Ord] }
53-
}
50+
patch = {
51+
SpIdentifier = { derives = [Copy, PartialEq, Eq, PartialOrd, Ord] },
52+
SpState = { derives = [ PartialEq, Eq, PartialOrd, Ord] },
53+
RotState = { derives = [ PartialEq, Eq, PartialOrd, Ord] },
54+
RotImageDetails = { derives = [ PartialEq, Eq, PartialOrd, Ord] },
55+
RotSlot = { derives = [ PartialEq, Eq, PartialOrd, Ord] },
56+
ImageVersion = { derives = [ PartialEq, Eq, PartialOrd, Ord] },
57+
},
5458
);

gateway/src/error.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
use crate::management_switch::SpIdentifier;
88
use dropshot::HttpError;
99
use gateway_messages::SpError;
10-
use gateway_sp_comms::error::CommunicationError;
10+
pub use gateway_sp_comms::error::CommunicationError;
1111
use gateway_sp_comms::error::UpdateError;
1212
use gateway_sp_comms::BindError;
1313
use std::time::Duration;

gateway/src/http_entrypoints.rs

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,13 +66,78 @@ pub struct SpInfo {
6666
pub enum SpState {
6767
Enabled {
6868
serial_number: String,
69-
// TODO more stuff
69+
model: String,
70+
revision: u32,
71+
hubris_archive_id: String,
72+
base_mac_address: [u8; 6],
73+
version: ImageVersion,
74+
power_state: PowerState,
75+
rot: RotState,
7076
},
7177
CommunicationFailed {
7278
message: String,
7379
},
7480
}
7581

82+
#[derive(
83+
Debug,
84+
Clone,
85+
PartialEq,
86+
Eq,
87+
PartialOrd,
88+
Ord,
89+
Deserialize,
90+
Serialize,
91+
JsonSchema,
92+
)]
93+
#[serde(tag = "state", rename_all = "snake_case")]
94+
pub enum RotState {
95+
// TODO gateway_messages's RotState includes a couple nested structures that
96+
// I've flattened here because they only contain one field each. When those
97+
// structures grow we'll need to expand/change this.
98+
Enabled {
99+
active: RotSlot,
100+
slot_a: Option<RotImageDetails>,
101+
slot_b: Option<RotImageDetails>,
102+
},
103+
CommunicationFailed {
104+
message: String,
105+
},
106+
}
107+
108+
#[derive(
109+
Debug,
110+
Clone,
111+
PartialEq,
112+
Eq,
113+
PartialOrd,
114+
Ord,
115+
Deserialize,
116+
Serialize,
117+
JsonSchema,
118+
)]
119+
#[serde(tag = "slot", rename_all = "snake_case")]
120+
pub enum RotSlot {
121+
A,
122+
B,
123+
}
124+
125+
#[derive(
126+
Debug,
127+
Clone,
128+
PartialEq,
129+
Eq,
130+
PartialOrd,
131+
Ord,
132+
Deserialize,
133+
Serialize,
134+
JsonSchema,
135+
)]
136+
pub struct RotImageDetails {
137+
pub digest: String,
138+
pub version: ImageVersion,
139+
}
140+
76141
#[derive(
77142
Debug,
78143
Clone,
@@ -309,12 +374,29 @@ pub struct HostStartupOptions {
309374
Deserialize,
310375
JsonSchema,
311376
)]
312-
enum PowerState {
377+
pub enum PowerState {
313378
A0,
314379
A1,
315380
A2,
316381
}
317382

383+
#[derive(
384+
Debug,
385+
Clone,
386+
Copy,
387+
PartialEq,
388+
Eq,
389+
PartialOrd,
390+
Ord,
391+
Serialize,
392+
Deserialize,
393+
JsonSchema,
394+
)]
395+
pub struct ImageVersion {
396+
pub epoch: u32,
397+
pub version: u32,
398+
}
399+
318400
/// Identifier for an SP's component's firmware slot; e.g., slots 0 and 1 for
319401
/// the host boot flash.
320402
#[derive(

gateway/src/http_entrypoints/conversions.rs

Lines changed: 62 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,11 @@
88
99
use super::HostStartupOptions;
1010
use super::IgnitionCommand;
11+
use super::ImageVersion;
1112
use super::PowerState;
13+
use super::RotImageDetails;
14+
use super::RotSlot;
15+
use super::RotState;
1216
use super::SpComponentInfo;
1317
use super::SpComponentList;
1418
use super::SpComponentPresence;
@@ -94,28 +98,78 @@ impl From<PowerState> for gateway_messages::PowerState {
9498
}
9599
}
96100

97-
fn stringify_serial_number(serial: &[u8]) -> String {
98-
// We expect serial numbers to be ASCII and 0-padded: find the first 0 byte
99-
// and convert to a string. If that fails, hexlify the entire slice.
100-
let first_zero =
101-
serial.iter().position(|&b| b == 0).unwrap_or(serial.len());
101+
impl From<gateway_messages::ImageVersion> for ImageVersion {
102+
fn from(v: gateway_messages::ImageVersion) -> Self {
103+
Self { epoch: v.epoch, version: v.version }
104+
}
105+
}
106+
107+
// We expect serial and model numbers to be ASCII and 0-padded: find the first 0
108+
// byte and convert to a string. If that fails, hexlify the entire slice.
109+
fn stringify_byte_string(bytes: &[u8]) -> String {
110+
let first_zero = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
102111

103-
str::from_utf8(&serial[..first_zero])
112+
str::from_utf8(&bytes[..first_zero])
104113
.map(|s| s.to_string())
105-
.unwrap_or_else(|_err| hex::encode(serial))
114+
.unwrap_or_else(|_err| hex::encode(bytes))
106115
}
107116

108117
impl From<Result<gateway_messages::SpState, SpCommsError>> for SpState {
109118
fn from(result: Result<gateway_messages::SpState, SpCommsError>) -> Self {
110119
match result {
111120
Ok(state) => Self::Enabled {
112-
serial_number: stringify_serial_number(&state.serial_number),
121+
serial_number: stringify_byte_string(&state.serial_number),
122+
model: stringify_byte_string(&state.model),
123+
revision: state.revision,
124+
hubris_archive_id: hex::encode(&state.hubris_archive_id),
125+
base_mac_address: state.base_mac_address,
126+
version: ImageVersion::from(state.version),
127+
power_state: PowerState::from(state.power_state),
128+
rot: RotState::from(state.rot),
113129
},
114130
Err(err) => Self::CommunicationFailed { message: err.to_string() },
115131
}
116132
}
117133
}
118134

135+
impl From<Result<gateway_messages::RotState, gateway_messages::RotError>>
136+
for RotState
137+
{
138+
fn from(
139+
result: Result<gateway_messages::RotState, gateway_messages::RotError>,
140+
) -> Self {
141+
match result {
142+
Ok(state) => {
143+
let boot_state = state.rot_updates.boot_state;
144+
Self::Enabled {
145+
active: boot_state.active.into(),
146+
slot_a: boot_state.slot_a.map(Into::into),
147+
slot_b: boot_state.slot_b.map(Into::into),
148+
}
149+
}
150+
Err(err) => Self::CommunicationFailed { message: err.to_string() },
151+
}
152+
}
153+
}
154+
155+
impl From<gateway_messages::RotSlot> for RotSlot {
156+
fn from(slot: gateway_messages::RotSlot) -> Self {
157+
match slot {
158+
gateway_messages::RotSlot::A => Self::A,
159+
gateway_messages::RotSlot::B => Self::B,
160+
}
161+
}
162+
}
163+
164+
impl From<gateway_messages::RotImageDetails> for RotImageDetails {
165+
fn from(details: gateway_messages::RotImageDetails) -> Self {
166+
Self {
167+
digest: hex::encode(&details.digest),
168+
version: details.version.into(),
169+
}
170+
}
171+
}
172+
119173
impl From<Result<gateway_messages::SpState, CommunicationError>> for SpState {
120174
fn from(
121175
result: Result<gateway_messages::SpState, CommunicationError>,

gateway/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ pub mod http_entrypoints; // TODO pub only for testing - is this right?
1212

1313
pub use config::Config;
1414
pub use context::ServerContext;
15+
pub use error::*;
16+
1517
use dropshot::ShutdownWaitFuture;
1618
use futures::stream::FuturesUnordered;
1719
use futures::StreamExt;

gateway/tests/integration_tests/location_discovery.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ async fn discovery_both_locations() {
4040

4141
let resp: SpInfo = test_util::object_get(client, &url).await;
4242
match resp.details {
43-
SpState::Enabled { serial_number } => {
43+
SpState::Enabled { serial_number, .. } => {
4444
assert_eq!(serial_number, expected_serial)
4545
}
4646
other => panic!("unexpected state {:?}", other),

gateway/tests/integration_tests/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ async fn current_simulator_state(simrack: &SimRack) -> Vec<SpInfo> {
7878

7979
let details =
8080
if matches!(target_state.power_state, SystemPowerState::On) {
81-
SpState::Enabled { serial_number: sp.serial_number() }
81+
sp.state().await
8282
} else {
8383
SpState::CommunicationFailed {
8484
message: "powered off".to_string(),

0 commit comments

Comments
 (0)