Skip to content

Commit c6628ce

Browse files
authored
Add cosmo ignition support (#9076)
1 parent bb796b6 commit c6628ce

File tree

15 files changed

+4502
-218
lines changed

15 files changed

+4502
-218
lines changed

Cargo.lock

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

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,9 @@ gateway-client = { path = "clients/gateway-client" }
461461
# compatibility, but will mean that faux-mgs might be missing new
462462
# functionality.)
463463
#
464-
gateway-ereport-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "77e316c812aa057b9714d0d99c4a7bdd36d45be2", default-features = false, features = ["debug-impls"] }
465-
gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "77e316c812aa057b9714d0d99c4a7bdd36d45be2", default-features = false, features = ["std"] }
466-
gateway-sp-comms = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "77e316c812aa057b9714d0d99c4a7bdd36d45be2" }
464+
gateway-ereport-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "6bd2660d651332f38949cdfd3d23d751ca54b120", default-features = false, features = ["debug-impls"] }
465+
gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "6bd2660d651332f38949cdfd3d23d751ca54b120", default-features = false, features = ["std"] }
466+
gateway-sp-comms = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "6bd2660d651332f38949cdfd3d23d751ca54b120" }
467467
gateway-test-utils = { path = "gateway-test-utils" }
468468
gateway-types = { path = "gateway-types" }
469469
gethostname = "0.5.0"

dev-tools/omdb/src/bin/omdb/mgs.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,9 @@ fn show_sps_from_ignition(
236236
id: SpIgnitionSystemType::Gimlet,
237237
..
238238
} => "Gimlet".to_string(),
239+
SpIgnition::Yes {
240+
id: SpIgnitionSystemType::Cosmo, ..
241+
} => "Cosmo".to_string(),
239242
SpIgnition::Yes {
240243
id: SpIgnitionSystemType::Sidecar,
241244
..

gateway-api/src/lib.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use gateway_types::{
1717
},
1818
component_details::SpComponentDetails,
1919
host::{ComponentFirmwareHashStatus, HostStartupOptions},
20+
ignition,
2021
ignition::{IgnitionCommand, SpIgnitionInfo},
2122
rot::{RotCfpa, RotCfpaSlot, RotCmpa, RotState},
2223
sensor::SpSensorReading,
@@ -45,6 +46,7 @@ api_versions!([
4546
// | example for the next person.
4647
// v
4748
// (next_int, IDENT),
49+
(2, COSMO),
4850
(1, INITIAL),
4951
]);
5052

@@ -407,6 +409,22 @@ pub trait GatewayApi {
407409
#[endpoint {
408410
method = GET,
409411
path = "/ignition",
412+
operation_id = "ignition_list",
413+
versions = VERSION_INITIAL..VERSION_COSMO
414+
}]
415+
async fn ignition_list_v1(
416+
rqctx: RequestContext<Self::Context>,
417+
) -> Result<HttpResponseOk<Vec<ignition::v1::SpIgnitionInfo>>, HttpError>;
418+
419+
/// List SPs via Ignition
420+
///
421+
/// Retreive information for all SPs via the Ignition controller. This is
422+
/// lower latency and has fewer possible failure modes than querying the SP
423+
/// over the management network.
424+
#[endpoint {
425+
method = GET,
426+
path = "/ignition",
427+
versions = VERSION_COSMO..
410428
}]
411429
async fn ignition_list(
412430
rqctx: RequestContext<Self::Context>,
@@ -420,6 +438,23 @@ pub trait GatewayApi {
420438
#[endpoint {
421439
method = GET,
422440
path = "/ignition/{type}/{slot}",
441+
operation_id = "ignition_get",
442+
versions = VERSION_INITIAL..VERSION_COSMO
443+
}]
444+
async fn ignition_get_v1(
445+
rqctx: RequestContext<Self::Context>,
446+
path: Path<PathSp>,
447+
) -> Result<HttpResponseOk<ignition::v1::SpIgnitionInfo>, HttpError>;
448+
449+
/// Get SP info via Ignition
450+
///
451+
/// Retreive information for an SP via the Ignition controller. This is
452+
/// lower latency and has fewer possible failure modes than querying the SP
453+
/// over the management network.
454+
#[endpoint {
455+
method = GET,
456+
path = "/ignition/{type}/{slot}",
457+
versions = VERSION_COSMO..
423458
}]
424459
async fn ignition_get(
425460
rqctx: RequestContext<Self::Context>,

gateway-test-utils/src/sim_state.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ pub async fn current_simulator_state(simrack: &SimRack) -> Vec<SpInfo> {
3636
};
3737
let typ = match target_state.system_type {
3838
SystemType::Sidecar => SpType::Switch,
39-
SystemType::Gimlet => SpType::Sled,
39+
SystemType::Gimlet | SystemType::Cosmo => SpType::Sled,
4040
SystemType::Psc => {
4141
todo!("testing simulated PSC not yet implemented")
4242
}

gateway-types/src/ignition/mod.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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 schemars::JsonSchema;
6+
use serde::{Deserialize, Serialize};
7+
8+
pub mod v1;
9+
pub mod v2;
10+
11+
pub use v2::*;
12+
13+
/// Ignition command.
14+
#[derive(
15+
Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema,
16+
)]
17+
#[serde(rename_all = "snake_case")]
18+
pub enum IgnitionCommand {
19+
PowerOn,
20+
PowerOff,
21+
PowerReset,
22+
}
23+
24+
impl From<IgnitionCommand> for gateway_messages::IgnitionCommand {
25+
fn from(cmd: IgnitionCommand) -> Self {
26+
match cmd {
27+
IgnitionCommand::PowerOn => {
28+
gateway_messages::IgnitionCommand::PowerOn
29+
}
30+
IgnitionCommand::PowerOff => {
31+
gateway_messages::IgnitionCommand::PowerOff
32+
}
33+
IgnitionCommand::PowerReset => {
34+
gateway_messages::IgnitionCommand::PowerReset
35+
}
36+
}
37+
}
38+
}

gateway-types/src/ignition.rs renamed to gateway-types/src/ignition/v1.rs

Lines changed: 2 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -79,33 +79,6 @@ impl From<gateway_messages::IgnitionState> for SpIgnition {
7979
}
8080
}
8181

82-
/// Ignition command.
83-
#[derive(
84-
Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize, JsonSchema,
85-
)]
86-
#[serde(rename_all = "snake_case")]
87-
pub enum IgnitionCommand {
88-
PowerOn,
89-
PowerOff,
90-
PowerReset,
91-
}
92-
93-
impl From<IgnitionCommand> for gateway_messages::IgnitionCommand {
94-
fn from(cmd: IgnitionCommand) -> Self {
95-
match cmd {
96-
IgnitionCommand::PowerOn => {
97-
gateway_messages::IgnitionCommand::PowerOn
98-
}
99-
IgnitionCommand::PowerOff => {
100-
gateway_messages::IgnitionCommand::PowerOff
101-
}
102-
IgnitionCommand::PowerReset => {
103-
gateway_messages::IgnitionCommand::PowerReset
104-
}
105-
}
106-
}
107-
}
108-
10982
/// TODO: Do we want to bake in specific board names, or use raw u16 ID numbers?
11083
#[derive(
11184
Debug,
@@ -135,6 +108,8 @@ impl From<gateway_messages::ignition::SystemType> for SpIgnitionSystemType {
135108
SystemType::Sidecar => Self::Sidecar,
136109
SystemType::Psc => Self::Psc,
137110
SystemType::Unknown(id) => Self::Unknown { id },
111+
// `0x4` is the ignition value per RFD 142
112+
SystemType::Cosmo => Self::Unknown { id: 0x4 },
138113
}
139114
}
140115
}

gateway-types/src/ignition/v2.rs

Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
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 schemars::JsonSchema;
6+
use serde::{Deserialize, Serialize};
7+
8+
use crate::component::SpIdentifier;
9+
10+
#[derive(
11+
Debug,
12+
Clone,
13+
PartialEq,
14+
Eq,
15+
PartialOrd,
16+
Ord,
17+
Deserialize,
18+
Serialize,
19+
JsonSchema,
20+
)]
21+
pub struct SpIgnitionInfo {
22+
pub id: SpIdentifier,
23+
pub details: SpIgnition,
24+
}
25+
26+
impl From<SpIgnitionInfo> for crate::ignition::v1::SpIgnitionInfo {
27+
fn from(s: SpIgnitionInfo) -> Self {
28+
Self { id: s.id, details: s.details.into() }
29+
}
30+
}
31+
32+
/// State of an ignition target.
33+
//
34+
// TODO: Ignition returns much more information than we're reporting here: do
35+
// we want to expand this?
36+
#[derive(
37+
Debug,
38+
Clone,
39+
PartialEq,
40+
Eq,
41+
PartialOrd,
42+
Ord,
43+
Deserialize,
44+
Serialize,
45+
JsonSchema,
46+
)]
47+
#[serde(tag = "present")]
48+
pub enum SpIgnition {
49+
#[serde(rename = "no")]
50+
Absent,
51+
#[serde(rename = "yes")]
52+
Present {
53+
id: SpIgnitionSystemType,
54+
power: bool,
55+
ctrl_detect_0: bool,
56+
ctrl_detect_1: bool,
57+
/// Fault from the A3 power domain
58+
flt_a3: bool,
59+
/// Fault from the A2 power domain
60+
flt_a2: bool,
61+
/// Fault from the RoT
62+
flt_rot: bool,
63+
/// Fault from the SP
64+
flt_sp: bool,
65+
},
66+
}
67+
68+
impl From<gateway_messages::IgnitionState> for SpIgnition {
69+
fn from(state: gateway_messages::IgnitionState) -> Self {
70+
use gateway_messages::ignition::SystemPowerState;
71+
72+
if let Some(target_state) = state.target {
73+
Self::Present {
74+
id: target_state.system_type.into(),
75+
power: matches!(
76+
target_state.power_state,
77+
SystemPowerState::On | SystemPowerState::PoweringOn
78+
),
79+
ctrl_detect_0: target_state.controller0_present,
80+
ctrl_detect_1: target_state.controller1_present,
81+
flt_a3: target_state.faults.power_a3,
82+
flt_a2: target_state.faults.power_a2,
83+
flt_rot: target_state.faults.rot,
84+
flt_sp: target_state.faults.sp,
85+
}
86+
} else {
87+
Self::Absent
88+
}
89+
}
90+
}
91+
92+
impl From<SpIgnition> for crate::ignition::v1::SpIgnition {
93+
fn from(state: SpIgnition) -> Self {
94+
match state {
95+
SpIgnition::Absent => Self::Absent,
96+
SpIgnition::Present {
97+
id,
98+
power,
99+
ctrl_detect_0,
100+
ctrl_detect_1,
101+
flt_a3,
102+
flt_a2,
103+
flt_rot,
104+
flt_sp,
105+
} => Self::Present {
106+
id: id.into(),
107+
power,
108+
ctrl_detect_0,
109+
ctrl_detect_1,
110+
flt_a3,
111+
flt_a2,
112+
flt_rot,
113+
flt_sp,
114+
},
115+
}
116+
}
117+
}
118+
119+
#[derive(
120+
Debug,
121+
Clone,
122+
Copy,
123+
PartialEq,
124+
Eq,
125+
PartialOrd,
126+
Ord,
127+
Deserialize,
128+
Serialize,
129+
JsonSchema,
130+
)]
131+
#[serde(tag = "system_type", rename_all = "snake_case")]
132+
pub enum SpIgnitionSystemType {
133+
Gimlet,
134+
Sidecar,
135+
Psc,
136+
Unknown { id: u16 },
137+
Cosmo,
138+
}
139+
140+
impl From<gateway_messages::ignition::SystemType> for SpIgnitionSystemType {
141+
fn from(st: gateway_messages::ignition::SystemType) -> Self {
142+
use gateway_messages::ignition::SystemType;
143+
match st {
144+
SystemType::Gimlet => Self::Gimlet,
145+
SystemType::Sidecar => Self::Sidecar,
146+
SystemType::Psc => Self::Psc,
147+
SystemType::Unknown(id) => Self::Unknown { id },
148+
SystemType::Cosmo => Self::Cosmo,
149+
}
150+
}
151+
}
152+
153+
impl From<SpIgnitionSystemType> for crate::ignition::v1::SpIgnitionSystemType {
154+
fn from(st: SpIgnitionSystemType) -> Self {
155+
match st {
156+
SpIgnitionSystemType::Gimlet => Self::Gimlet,
157+
SpIgnitionSystemType::Sidecar => Self::Sidecar,
158+
SpIgnitionSystemType::Psc => Self::Psc,
159+
// Cosmo system id is 0x4
160+
SpIgnitionSystemType::Cosmo => Self::Unknown { id: 0x4 },
161+
SpIgnitionSystemType::Unknown { id } => Self::Unknown { id },
162+
}
163+
}
164+
}

gateway/src/http_entrypoints.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ use gateway_types::component::SpState;
4040
use gateway_types::component_details::SpComponentDetails;
4141
use gateway_types::host::ComponentFirmwareHashStatus;
4242
use gateway_types::host::HostStartupOptions;
43+
use gateway_types::ignition;
4344
use gateway_types::ignition::SpIgnitionInfo;
4445
use gateway_types::rot::RotCfpa;
4546
use gateway_types::rot::RotCfpaSlot;
@@ -825,6 +826,19 @@ impl GatewayApi for GatewayImpl {
825826
apictx.latencies.instrument_dropshot_handler(&rqctx, handler).await
826827
}
827828

829+
async fn ignition_list_v1(
830+
rqctx: RequestContext<Self::Context>,
831+
) -> Result<HttpResponseOk<Vec<ignition::v1::SpIgnitionInfo>>, HttpError>
832+
{
833+
let HttpResponseOk(v2_info) = Self::ignition_list(rqctx).await?;
834+
Ok(HttpResponseOk(
835+
v2_info
836+
.into_iter()
837+
.map(|x| ignition::v1::SpIgnitionInfo::from(x))
838+
.collect(),
839+
))
840+
}
841+
828842
async fn ignition_list(
829843
rqctx: RequestContext<Self::Context>,
830844
) -> Result<HttpResponseOk<Vec<SpIgnitionInfo>>, HttpError> {
@@ -845,6 +859,14 @@ impl GatewayApi for GatewayImpl {
845859
apictx.latencies.instrument_dropshot_handler(&rqctx, handler).await
846860
}
847861

862+
async fn ignition_get_v1(
863+
rqctx: RequestContext<Self::Context>,
864+
path: Path<PathSp>,
865+
) -> Result<HttpResponseOk<ignition::v1::SpIgnitionInfo>, HttpError> {
866+
let HttpResponseOk(v2_info) = Self::ignition_get(rqctx, path).await?;
867+
Ok(HttpResponseOk(ignition::v1::SpIgnitionInfo::from(v2_info)))
868+
}
869+
848870
async fn ignition_get(
849871
rqctx: RequestContext<Self::Context>,
850872
path: Path<PathSp>,

gateway/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ fn start_dropshot_server(
106106
.version_policy(dropshot::VersionPolicy::Dynamic(Box::new(
107107
dropshot::ClientSpecifiesVersionInHeader::new(
108108
omicron_common::api::VERSION_HEADER,
109-
gateway_api::VERSION_INITIAL,
109+
gateway_api::VERSION_COSMO,
110110
),
111111
)))
112112
.start()

0 commit comments

Comments
 (0)