Skip to content
Merged
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
46 changes: 24 additions & 22 deletions gateway/src/http_entrypoints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ use dropshot::UntypedBody;
use dropshot::WebsocketEndpointResult;
use dropshot::WebsocketUpgrade;
use futures::TryFutureExt;
use gateway_messages::SpComponent;
use gateway_messages::SpError;
use gateway_sp_comms::error::CommunicationError;
use gateway_sp_comms::HostPhase2Provider;
Expand Down Expand Up @@ -58,7 +57,6 @@ pub struct SpState {
pub revision: u32,
pub hubris_archive_id: String,
pub base_mac_address: [u8; 6],
pub version: ImageVersion,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👯

pub power_state: PowerState,
pub rot: RotState,
}
Expand All @@ -76,13 +74,13 @@ pub struct SpState {
)]
#[serde(tag = "state", rename_all = "snake_case")]
pub enum RotState {
// TODO gateway_messages's RotState includes a couple nested structures that
// I've flattened here because they only contain one field each. When those
// structures grow we'll need to expand/change this.
Enabled {
active: RotSlot,
slot_a: Option<RotImageDetails>,
slot_b: Option<RotImageDetails>,
persistent_boot_preference: RotSlot,
pending_persistent_boot_preference: Option<RotSlot>,
transient_boot_preference: Option<RotSlot>,
slot_a_sha3_256_digest: Option<String>,
slot_b_sha3_256_digest: Option<String>,
},
CommunicationFailed {
message: String,
Expand Down Expand Up @@ -619,6 +617,7 @@ async fn sp_component_get(
async fn sp_component_caboose_get(
rqctx: RequestContext<Arc<ServerContext>>,
path: Path<PathSpComponent>,
query_params: Query<ComponentCabooseSlot>,
) -> Result<HttpResponseOk<SpComponentCaboose>, HttpError> {
const CABOOSE_KEY_GIT_COMMIT: [u8; 4] = *b"GITC";
const CABOOSE_KEY_BOARD: [u8; 4] = *b"BORD";
Expand All @@ -628,18 +627,8 @@ async fn sp_component_caboose_get(
let apictx = rqctx.context();
let PathSpComponent { sp, component } = path.into_inner();
let sp = apictx.mgmt_switch.sp(sp.into())?;

// At the moment this endpoint only works if the requested component
// is the SP itself; we have no way (yet!) of asking the SP for (e.g.) RoT
// caboose values.
let ComponentCabooseSlot { firmware_slot } = query_params.into_inner();
let component = component_from_str(&component)?;
if component != SpComponent::SP_ITSELF {
return Err(HttpError::from(SpCommsError::from(
CommunicationError::SpError(
SpError::RequestUnsupportedForComponent,
),
)));
}

let from_utf8 = |key: &[u8], bytes| {
// This helper closure is only called with the ascii-printable [u8; 4]
Expand All @@ -655,18 +644,25 @@ async fn sp_component_caboose_get(
};

let git_commit = sp
.get_caboose_value(CABOOSE_KEY_GIT_COMMIT)
.read_component_caboose(
component,
firmware_slot,
CABOOSE_KEY_GIT_COMMIT,
)
.await
.map_err(SpCommsError::from)?;
let board = sp
.get_caboose_value(CABOOSE_KEY_BOARD)
.read_component_caboose(component, firmware_slot, CABOOSE_KEY_BOARD)
.await
.map_err(SpCommsError::from)?;
let name = sp
.get_caboose_value(CABOOSE_KEY_NAME)
.read_component_caboose(component, firmware_slot, CABOOSE_KEY_NAME)
.await
.map_err(SpCommsError::from)?;
let version = match sp.get_caboose_value(CABOOSE_KEY_VERSION).await {
let version = match sp
.read_component_caboose(component, firmware_slot, CABOOSE_KEY_VERSION)
.await
{
Ok(value) => Some(from_utf8(&CABOOSE_KEY_VERSION, value)?),
Err(CommunicationError::SpError(SpError::NoSuchCabooseKey(_))) => None,
Err(err) => return Err(SpCommsError::from(err).into()),
Expand Down Expand Up @@ -838,6 +834,12 @@ pub struct ComponentUpdateIdSlot {
pub firmware_slot: u16,
}

#[derive(Deserialize, JsonSchema)]
pub struct ComponentCabooseSlot {
/// The firmware slot to for which we want to request caboose information.
pub firmware_slot: u16,
}

#[derive(Deserialize, JsonSchema)]
pub struct UpdateAbortBody {
/// The ID of the update to abort.
Expand Down
54 changes: 31 additions & 23 deletions gateway/src/http_entrypoints/conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,6 @@ impl From<gateway_messages::SpStateV1> for SpState {
revision: state.revision,
hubris_archive_id: hex::encode(state.hubris_archive_id),
base_mac_address: state.base_mac_address,
version: ImageVersion::from(state.version),
power_state: PowerState::from(state.power_state),
rot: RotState::from(state.rot),
}
Expand All @@ -139,7 +138,6 @@ impl From<gateway_messages::SpStateV2> for SpState {
revision: state.revision,
hubris_archive_id: hex::encode(state.hubris_archive_id),
base_mac_address: state.base_mac_address,
version: ImageVersion { epoch: 0, version: 0 }, // TODO FIXME
power_state: PowerState::from(state.power_state),
rot: RotState::from(state.rot),
}
Expand All @@ -166,16 +164,26 @@ impl From<Result<gateway_messages::RotState, gateway_messages::RotError>>
let boot_state = state.rot_updates.boot_state;
Self::Enabled {
active: boot_state.active.into(),
slot_a: boot_state.slot_a.map(Into::into),
slot_b: boot_state.slot_b.map(Into::into),
slot_a_sha3_256_digest: boot_state
.slot_a
.map(|details| hex::encode(details.digest)),
slot_b_sha3_256_digest: boot_state
.slot_b
.map(|details| hex::encode(details.digest)),
// RotState(V1) didn't have the following fields, so we make
// it up as best we can. This RoT version is pre-shipping
// and should only exist on (not updated recently) test
// systems.
persistent_boot_preference: boot_state.active.into(),
pending_persistent_boot_preference: None,
transient_boot_preference: None,
}
}
Err(err) => Self::CommunicationFailed { message: err.to_string() },
}
}
}

// TODO FIXME
impl From<Result<gateway_messages::RotStateV2, gateway_messages::RotError>>
for RotState
{
Expand All @@ -186,24 +194,24 @@ impl From<Result<gateway_messages::RotStateV2, gateway_messages::RotError>>
>,
) -> Self {
match result {
Ok(state) => {
// TODO FIXME: This is wrong for RotStateV2
Self::Enabled {
active: state.active.into(),
slot_a: state.slot_a_sha3_256_digest.map(|hash| {
RotImageDetails {
digest: hex::encode(hash),
version: ImageVersion { epoch: 0, version: 0 },
}
}),
slot_b: state.slot_b_sha3_256_digest.map(|hash| {
RotImageDetails {
digest: hex::encode(hash),
version: ImageVersion { epoch: 0, version: 0 },
}
}),
}
}
Ok(state) => Self::Enabled {
active: state.active.into(),
persistent_boot_preference: state
.persistent_boot_preference
.into(),
pending_persistent_boot_preference: state
.pending_persistent_boot_preference
.map(Into::into),
transient_boot_preference: state
.transient_boot_preference
.map(Into::into),
slot_a_sha3_256_digest: state
.slot_a_sha3_256_digest
.map(hex::encode),
slot_b_sha3_256_digest: state
.slot_b_sha3_256_digest
.map(hex::encode),
},
Err(err) => Self::CommunicationFailed { message: err.to_string() },
}
}
Expand Down
79 changes: 32 additions & 47 deletions openapi/gateway.json
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,17 @@
"schema": {
"$ref": "#/components/schemas/SpType"
}
},
{
"in": "query",
"name": "firmware_slot",
"description": "The firmware slot to for which we want to request caboose information.",
"required": true,
"schema": {
"type": "integer",
"format": "uint16",
"minimum": 0
}
}
],
"responses": {
Expand Down Expand Up @@ -1423,25 +1434,6 @@
"verbose"
]
},
"ImageVersion": {
"type": "object",
"properties": {
"epoch": {
"type": "integer",
"format": "uint32",
"minimum": 0
},
"version": {
"type": "integer",
"format": "uint32",
"minimum": 0
}
},
"required": [
"epoch",
"version"
]
},
"InstallinatorImageId": {
"type": "object",
"properties": {
Expand Down Expand Up @@ -2079,21 +2071,6 @@
"A2"
]
},
"RotImageDetails": {
"type": "object",
"properties": {
"digest": {
"type": "string"
},
"version": {
"$ref": "#/components/schemas/ImageVersion"
}
},
"required": [
"digest",
"version"
]
},
"RotSlot": {
"oneOf": [
{
Expand Down Expand Up @@ -2134,31 +2111,43 @@
"active": {
"$ref": "#/components/schemas/RotSlot"
},
"slot_a": {
"pending_persistent_boot_preference": {
"nullable": true,
"allOf": [
{
"$ref": "#/components/schemas/RotImageDetails"
"$ref": "#/components/schemas/RotSlot"
}
]
},
"slot_b": {
"persistent_boot_preference": {
"$ref": "#/components/schemas/RotSlot"
},
"slot_a_sha3_256_digest": {
"nullable": true,
"allOf": [
{
"$ref": "#/components/schemas/RotImageDetails"
}
]
"type": "string"
},
"slot_b_sha3_256_digest": {
"nullable": true,
"type": "string"
},
"state": {
"type": "string",
"enum": [
"enabled"
]
},
"transient_boot_preference": {
"nullable": true,
"allOf": [
{
"$ref": "#/components/schemas/RotSlot"
}
]
}
},
"required": [
"active",
"persistent_boot_preference",
"state"
]
},
Expand Down Expand Up @@ -2642,9 +2631,6 @@
},
"serial_number": {
"type": "string"
},
"version": {
"$ref": "#/components/schemas/ImageVersion"
}
},
"required": [
Expand All @@ -2654,8 +2640,7 @@
"power_state",
"revision",
"rot",
"serial_number",
"version"
"serial_number"
]
},
"SpType": {
Expand Down
Loading