Skip to content

Commit 5abd800

Browse files
committed
return hash status instead of custom errors
1 parent f255b54 commit 5abd800

File tree

10 files changed

+93
-204
lines changed

10 files changed

+93
-204
lines changed

Cargo.lock

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

gateway-api/src/lib.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@ use gateway_types::{
1616
SpState,
1717
},
1818
component_details::SpComponentDetails,
19-
error::ComponentFlashError,
20-
host::HostStartupOptions,
19+
host::{ComponentFirmwareHashStatus, HostStartupOptions},
2120
ignition::{IgnitionCommand, SpIgnitionInfo},
2221
rot::{RotCfpa, RotCfpaSlot, RotCmpa, RotState},
2322
sensor::SpSensorReading,
@@ -28,7 +27,7 @@ use gateway_types::{
2827
},
2928
};
3029
use schemars::JsonSchema;
31-
use serde::{Deserialize, Serialize};
30+
use serde::Deserialize;
3231
use uuid::Uuid;
3332

3433
/// This endpoint is used to upload SP and ROT Hubris archives as well as phase 1 host OS
@@ -273,7 +272,7 @@ pub trait GatewayApi {
273272
async fn sp_component_hash_firmware_start(
274273
rqctx: RequestContext<Self::Context>,
275274
path: Path<PathSpComponentFirmwareSlot>,
276-
) -> Result<HttpResponseUpdatedNoContent, ComponentFlashError>;
275+
) -> Result<HttpResponseUpdatedNoContent, HttpError>;
277276

278277
/// Get a computed hash of a given slot of a component.
279278
///
@@ -288,7 +287,7 @@ pub trait GatewayApi {
288287
async fn sp_component_hash_firmware_get(
289288
rqctx: RequestContext<Self::Context>,
290289
path: Path<PathSpComponentFirmwareSlot>,
291-
) -> Result<HttpResponseOk<ComponentFirmwareHash>, ComponentFlashError>;
290+
) -> Result<HttpResponseOk<ComponentFirmwareHashStatus>, HttpError>;
292291

293292
/// Abort any in-progress update an SP component
294293
///
@@ -659,8 +658,3 @@ pub struct PathSpIgnitionCommand {
659658
/// Ignition command to perform on the targeted SP.
660659
pub command: IgnitionCommand,
661660
}
662-
663-
#[derive(Serialize, Deserialize, JsonSchema)]
664-
pub struct ComponentFirmwareHash {
665-
pub sha256: [u8; 32],
666-
}

gateway-types/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ workspace = true
99

1010
[dependencies]
1111
daft.workspace = true
12-
dropshot.workspace = true
1312
gateway-messages.workspace = true
1413
# Avoid depending on gateway-sp-comms! It is a pretty heavy dependency and
1514
# would only be used for From impls anyway. We put those impls in
@@ -21,6 +20,5 @@ omicron-uuid-kinds.workspace = true
2120
omicron-workspace-hack.workspace = true
2221
schemars.workspace = true
2322
serde.workspace = true
24-
thiserror.workspace = true
2523
tufaceous-artifact.workspace = true
2624
uuid.workspace = true

gateway-types/src/error.rs

Lines changed: 0 additions & 56 deletions
This file was deleted.

gateway-types/src/host.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,18 @@ impl From<StartupOptions> for HostStartupOptions {
5656
}
5757
}
5858
}
59+
60+
#[derive(Serialize, Deserialize, JsonSchema)]
61+
#[serde(tag = "status", rename_all = "snake_case")]
62+
pub enum ComponentFirmwareHashStatus {
63+
/// The hash is not available; the client must issue a separate request to
64+
/// begin calculating the hash.
65+
HashNotCalculated,
66+
/// The hash is currently being calculated; the client should sleep briefly
67+
/// then check again.
68+
///
69+
/// We expect this operation to take a handful of seconds in practice.
70+
HashInProgress,
71+
/// The hash of the given firmware slot.
72+
Hashed { sha256: [u8; 32] },
73+
}

gateway-types/src/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
pub mod caboose;
88
pub mod component;
99
pub mod component_details;
10-
pub mod error;
1110
pub mod host;
1211
pub mod ignition;
1312
pub mod rot;

gateway/src/error.rs

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,10 @@
66
77
use crate::management_switch::SpIdentifier;
88
use dropshot::HttpError;
9-
use gateway_messages::HfError;
109
use gateway_messages::SpError;
1110
use gateway_sp_comms::BindError;
1211
pub use gateway_sp_comms::error::CommunicationError;
1312
use gateway_sp_comms::error::UpdateError;
14-
use gateway_types::error::ComponentFlashError;
1513
use slog_error_chain::InlineErrorChain;
1614
use slog_error_chain::SlogInlineError;
1715
use std::error::Error;
@@ -234,33 +232,3 @@ pub(crate) fn http_err_with_message(
234232
headers: None,
235233
}
236234
}
237-
238-
/// Convert a `CommunicationError` with a given `sp` into a
239-
/// `ComponentFlashError`.
240-
pub(crate) fn map_component_flash_error(
241-
sp: SpIdentifier,
242-
err: CommunicationError,
243-
) -> ComponentFlashError {
244-
if let CommunicationError::SpError(err) = &err {
245-
if let SpError::Hf(err) = err {
246-
match err {
247-
HfError::HashUncalculated => {
248-
return ComponentFlashError::HashUncalculated;
249-
}
250-
HfError::RecalculateHash => {
251-
return ComponentFlashError::HashStale;
252-
}
253-
HfError::HashInProgress => {
254-
return ComponentFlashError::HashInProgress;
255-
}
256-
HfError::NotMuxedToSp
257-
| HfError::BadAddress
258-
| HfError::QspiTimeout
259-
| HfError::QspiTransferError => (),
260-
}
261-
}
262-
}
263-
ComponentFlashError::from(HttpError::from(
264-
SpCommsError::SpCommunicationFailed { sp, err },
265-
))
266-
}

gateway/src/http_entrypoints.rs

Lines changed: 41 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
use crate::ServerContext;
1010
use crate::error::SpCommsError;
1111
use crate::http_err_with_message;
12-
use crate::map_component_flash_error;
1312
use base64::Engine;
1413
use dropshot::ApiDescription;
1514
use dropshot::HttpError;
@@ -24,8 +23,10 @@ use dropshot::WebsocketEndpointResult;
2423
use dropshot::WebsocketUpgrade;
2524
use futures::TryFutureExt;
2625
use gateway_api::*;
26+
use gateway_messages::HfError;
2727
use gateway_messages::RotBootInfo;
2828
use gateway_messages::SpComponent;
29+
use gateway_messages::SpError;
2930
use gateway_sp_comms::HostPhase2Provider;
3031
use gateway_sp_comms::VersionedSpState;
3132
use gateway_sp_comms::error::CommunicationError;
@@ -37,7 +38,7 @@ use gateway_types::component::SpComponentList;
3738
use gateway_types::component::SpIdentifier;
3839
use gateway_types::component::SpState;
3940
use gateway_types::component_details::SpComponentDetails;
40-
use gateway_types::error::ComponentFlashError;
41+
use gateway_types::host::ComponentFirmwareHashStatus;
4142
use gateway_types::host::HostStartupOptions;
4243
use gateway_types::ignition::SpIgnitionInfo;
4344
use gateway_types::rot::RotCfpa;
@@ -541,28 +542,27 @@ impl GatewayApi for GatewayImpl {
541542
async fn sp_component_hash_firmware_start(
542543
rqctx: RequestContext<Self::Context>,
543544
path: Path<PathSpComponentFirmwareSlot>,
544-
) -> Result<HttpResponseUpdatedNoContent, ComponentFlashError> {
545+
) -> Result<HttpResponseUpdatedNoContent, HttpError> {
545546
let apictx = rqctx.context();
546547

547548
let PathSpComponentFirmwareSlot { sp, component, firmware_slot } =
548549
path.into_inner();
549550
let sp_id = sp.into();
550551
let handler = async {
551-
let sp = apictx.mgmt_switch.sp(sp_id).map_err(HttpError::from)?;
552+
let sp = apictx.mgmt_switch.sp(sp_id)?;
552553
let component = component_from_str(&component)?;
553554

554555
if component != SpComponent::HOST_CPU_BOOT_FLASH {
555-
return Err(ComponentFlashError::from(
556-
HttpError::for_bad_request(
557-
Some("RequestUnsupportedForComponent".to_string()),
558-
"Only the host boot flash can be hashed".into(),
559-
),
556+
return Err(HttpError::for_bad_request(
557+
Some("RequestUnsupportedForComponent".to_string()),
558+
"Only the host boot flash can be hashed".into(),
560559
));
561560
}
562561

563-
sp.start_host_flash_hash(firmware_slot)
564-
.await
565-
.map_err(|err| map_component_flash_error(sp_id, err))?;
562+
// TODO-john catch hash in progress?
563+
sp.start_host_flash_hash(firmware_slot).await.map_err(|err| {
564+
SpCommsError::SpCommunicationFailed { sp: sp_id, err }
565+
})?;
566566

567567
Ok(HttpResponseUpdatedNoContent())
568568
};
@@ -572,32 +572,48 @@ impl GatewayApi for GatewayImpl {
572572
async fn sp_component_hash_firmware_get(
573573
rqctx: RequestContext<Self::Context>,
574574
path: Path<PathSpComponentFirmwareSlot>,
575-
) -> Result<HttpResponseOk<ComponentFirmwareHash>, ComponentFlashError>
576-
{
575+
) -> Result<HttpResponseOk<ComponentFirmwareHashStatus>, HttpError> {
577576
let apictx = rqctx.context();
578577

579578
let PathSpComponentFirmwareSlot { sp, component, firmware_slot } =
580579
path.into_inner();
581580
let sp_id = sp.into();
582581
let handler = async {
583-
let sp = apictx.mgmt_switch.sp(sp_id).map_err(HttpError::from)?;
582+
let sp = apictx.mgmt_switch.sp(sp_id)?;
584583
let component = component_from_str(&component)?;
585584

586585
if component != SpComponent::HOST_CPU_BOOT_FLASH {
587-
return Err(ComponentFlashError::from(
588-
HttpError::for_bad_request(
589-
Some("RequestUnsupportedForComponent".to_string()),
590-
"Only the host boot flash can be hashed".into(),
591-
),
586+
return Err(HttpError::for_bad_request(
587+
Some("RequestUnsupportedForComponent".to_string()),
588+
"Only the host boot flash can be hashed".into(),
592589
));
593590
}
594591

595-
let sha256 = sp
596-
.get_host_flash_hash(firmware_slot)
597-
.await
598-
.map_err(|err| map_component_flash_error(sp_id, err))?;
592+
let status = match sp.get_host_flash_hash(firmware_slot).await {
593+
// success
594+
Ok(sha256) => ComponentFirmwareHashStatus::Hashed { sha256 },
595+
596+
// expected failure: hash needs to be calculated (or
597+
// recalculated; either way the client operation is the same)
598+
Err(CommunicationError::SpError(SpError::Hf(
599+
HfError::HashUncalculated | HfError::RecalculateHash,
600+
))) => ComponentFirmwareHashStatus::HashNotCalculated,
601+
602+
// expected failure: hashing is currently in progress; client
603+
// needs to wait and try again later
604+
Err(CommunicationError::SpError(SpError::Hf(
605+
HfError::HashInProgress,
606+
))) => ComponentFirmwareHashStatus::HashInProgress,
607+
608+
// other errors are failures
609+
Err(err) => {
610+
return Err(HttpError::from(
611+
SpCommsError::SpCommunicationFailed { sp: sp_id, err },
612+
));
613+
}
614+
};
599615

600-
Ok(HttpResponseOk(ComponentFirmwareHash { sha256 }))
616+
Ok(HttpResponseOk(status))
601617
};
602618
apictx.latencies.instrument_dropshot_handler(&rqctx, handler).await
603619
}

nexus/mgs-updates/tests/host_phase1_hash.rs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,11 @@
88
//! ask it to start hashing, then we'll get "still hashing" errors for a few
99
//! seconds, then we'll get the hash result.
1010
11-
use gateway_client::Error;
1211
use gateway_client::SpComponent;
13-
use gateway_client::types::ComponentFlashError;
12+
use gateway_client::types::ComponentFirmwareHashStatus;
1413
use gateway_client::types::SpType;
1514
use gateway_messages::SpPort;
1615
use gateway_test_utils::setup as mgs_setup;
17-
use slog_error_chain::InlineErrorChain;
1816

1917
#[tokio::test]
2018
async fn test_host_phase1_hashing() {
@@ -34,23 +32,18 @@ async fn test_host_phase1_hashing() {
3432
// We haven't yet started hashing; we should get the error we expect for
3533
// both slots.
3634
for firmware_slot in [0, 1] {
37-
match mgs_client
35+
let status = mgs_client
3836
.sp_component_hash_firmware_get(
3937
sp_type,
4038
sp_slot,
4139
sp_component,
4240
firmware_slot,
4341
)
4442
.await
45-
{
46-
Err(Error::ErrorResponse(err)) => match err.into_inner() {
47-
ComponentFlashError::HashUncalculated => (),
48-
other => panic!("unexpected error response: {other:?}"),
49-
},
50-
Err(err) => {
51-
panic!("unexpected error: {}", InlineErrorChain::new(&err))
52-
}
53-
Ok(resp) => panic!("unexpected success: {resp:?}"),
43+
.expect("got firmware hash status");
44+
match status.into_inner() {
45+
ComponentFirmwareHashStatus::HashNotCalculated => (),
46+
other => panic!("unexpected status: {other:?}"),
5447
}
5548
}
5649
}

0 commit comments

Comments
 (0)