Skip to content

Commit 4667e49

Browse files
committed
Add cosmo ignition support
1 parent 45c7381 commit 4667e49

File tree

13 files changed

+4370
-101
lines changed

13 files changed

+4370
-101
lines changed

Cargo.lock

Lines changed: 65 additions & 66 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 = "ad5f86ce59029dbc9154d1ec65e2e988ed50628a", default-features = false, features = ["debug-impls"] }
465+
gateway-messages = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "ad5f86ce59029dbc9154d1ec65e2e988ed50628a", default-features = false, features = ["std"] }
466+
gateway-sp-comms = { git = "https://github.com/oxidecomputer/management-gateway-service", rev = "ad5f86ce59029dbc9154d1ec65e2e988ed50628a" }
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: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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+
/// State of an ignition target.
27+
//
28+
// TODO: Ignition returns much more information than we're reporting here: do
29+
// we want to expand this?
30+
#[derive(
31+
Debug,
32+
Clone,
33+
PartialEq,
34+
Eq,
35+
PartialOrd,
36+
Ord,
37+
Deserialize,
38+
Serialize,
39+
JsonSchema,
40+
)]
41+
#[serde(tag = "present")]
42+
pub enum SpIgnition {
43+
#[serde(rename = "no")]
44+
Absent,
45+
#[serde(rename = "yes")]
46+
Present {
47+
id: SpIgnitionSystemType,
48+
power: bool,
49+
ctrl_detect_0: bool,
50+
ctrl_detect_1: bool,
51+
/// Fault from the A3 power domain
52+
flt_a3: bool,
53+
/// Fault from the A2 power domain
54+
flt_a2: bool,
55+
/// Fault from the RoT
56+
flt_rot: bool,
57+
/// Fault from the SP
58+
flt_sp: bool,
59+
},
60+
}
61+
62+
impl From<gateway_messages::IgnitionState> for SpIgnition {
63+
fn from(state: gateway_messages::IgnitionState) -> Self {
64+
use gateway_messages::ignition::SystemPowerState;
65+
66+
if let Some(target_state) = state.target {
67+
Self::Present {
68+
id: target_state.system_type.into(),
69+
power: matches!(
70+
target_state.power_state,
71+
SystemPowerState::On | SystemPowerState::PoweringOn
72+
),
73+
ctrl_detect_0: target_state.controller0_present,
74+
ctrl_detect_1: target_state.controller1_present,
75+
flt_a3: target_state.faults.power_a3,
76+
flt_a2: target_state.faults.power_a2,
77+
flt_rot: target_state.faults.rot,
78+
flt_sp: target_state.faults.sp,
79+
}
80+
} else {
81+
Self::Absent
82+
}
83+
}
84+
}
85+
86+
#[derive(
87+
Debug,
88+
Clone,
89+
Copy,
90+
PartialEq,
91+
Eq,
92+
PartialOrd,
93+
Ord,
94+
Deserialize,
95+
Serialize,
96+
JsonSchema,
97+
)]
98+
#[serde(tag = "system_type", rename_all = "snake_case")]
99+
pub enum SpIgnitionSystemType {
100+
Gimlet,
101+
Sidecar,
102+
Psc,
103+
Unknown { id: u16 },
104+
Cosmo,
105+
}
106+
107+
impl From<gateway_messages::ignition::SystemType> for SpIgnitionSystemType {
108+
fn from(st: gateway_messages::ignition::SystemType) -> Self {
109+
use gateway_messages::ignition::SystemType;
110+
match st {
111+
SystemType::Gimlet => Self::Gimlet,
112+
SystemType::Sidecar => Self::Sidecar,
113+
SystemType::Psc => Self::Psc,
114+
SystemType::Unknown(id) => Self::Unknown { id },
115+
SystemType::Cosmo => Self::Cosmo,
116+
}
117+
}
118+
}

gateway/src/http_entrypoints.rs

Lines changed: 51 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,27 @@ 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 apictx = rqctx.context();
834+
let mgmt_switch = &apictx.mgmt_switch;
835+
let handler = async {
836+
let out = mgmt_switch
837+
.bulk_ignition_state()
838+
.await?
839+
.map(|(id, state)| ignition::v1::SpIgnitionInfo {
840+
id: id.into(),
841+
details: state.into(),
842+
})
843+
.collect();
844+
845+
Ok(HttpResponseOk(out))
846+
};
847+
apictx.latencies.instrument_dropshot_handler(&rqctx, handler).await
848+
}
849+
828850
async fn ignition_list(
829851
rqctx: RequestContext<Self::Context>,
830852
) -> Result<HttpResponseOk<Vec<SpIgnitionInfo>>, HttpError> {
@@ -845,6 +867,35 @@ impl GatewayApi for GatewayImpl {
845867
apictx.latencies.instrument_dropshot_handler(&rqctx, handler).await
846868
}
847869

870+
async fn ignition_get_v1(
871+
rqctx: RequestContext<Self::Context>,
872+
path: Path<PathSp>,
873+
) -> Result<HttpResponseOk<ignition::v1::SpIgnitionInfo>, HttpError> {
874+
let apictx = rqctx.context();
875+
let mgmt_switch = &apictx.mgmt_switch;
876+
877+
let sp_id = path.into_inner().sp.into();
878+
let handler = async {
879+
let ignition_target = mgmt_switch.ignition_target(sp_id)?;
880+
881+
let state = mgmt_switch
882+
.ignition_controller()
883+
.ignition_state(ignition_target)
884+
.await
885+
.map_err(|err| SpCommsError::SpCommunicationFailed {
886+
sp: sp_id,
887+
err,
888+
})?;
889+
890+
let info = ignition::v1::SpIgnitionInfo {
891+
id: sp_id.into(),
892+
details: state.into(),
893+
};
894+
Ok(HttpResponseOk(info))
895+
};
896+
apictx.latencies.instrument_dropshot_handler(&rqctx, handler).await
897+
}
898+
848899
async fn ignition_get(
849900
rqctx: RequestContext<Self::Context>,
850901
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)