Skip to content

Commit abb5f25

Browse files
authored
[nexus-mgs-updates] Remove unused component updaters (#8849)
Followup from #8737 (comment). These have served a purpose (showing how to update components via MGS), but are not how we're actually delivering updates. Our Reconfigurator-based updaters have their own tests and are now implemented, so we can prune these.
1 parent 778d6e6 commit abb5f25

File tree

8 files changed

+2
-2736
lines changed

8 files changed

+2
-2736
lines changed

nexus/mgs-updates/src/common_sp_update.rs

Lines changed: 1 addition & 201 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
//! updates.
77
88
use super::MgsClients;
9-
use super::UpdateProgress;
109
use crate::host_phase1_updater::ReconfiguratorHostPhase1Updater;
1110
use crate::mgs_clients::GatewaySpComponentResetError;
1211
use crate::mgs_clients::RetryableMgsError;
@@ -15,18 +14,15 @@ use crate::rot_updater::ReconfiguratorRotUpdater;
1514
use crate::sp_updater::ReconfiguratorSpUpdater;
1615
use futures::future::BoxFuture;
1716
use gateway_client::types::SpType;
18-
use gateway_client::types::SpUpdateStatus;
1917
use gateway_types::rot::RotSlot;
2018
use nexus_types::deployment::ExpectedVersion;
2119
use nexus_types::deployment::PendingMgsUpdate;
2220
use nexus_types::deployment::PendingMgsUpdateDetails;
2321
use omicron_common::disk::M2Slot;
24-
use slog::Logger;
25-
use slog::{debug, error, info, warn};
22+
use slog::error;
2623
use std::net::SocketAddrV6;
2724
use std::time::Duration;
2825
use thiserror::Error;
29-
use tokio::sync::watch;
3026
use tufaceous_artifact::ArtifactHash;
3127
use tufaceous_artifact::ArtifactKind;
3228
use tufaceous_artifact::ArtifactVersion;
@@ -69,202 +65,6 @@ pub enum SpComponentUpdateError {
6965
UpdateFailedWithMessage(String),
7066
}
7167

72-
/// Describes an update to a component for which the SP drives the update
73-
///
74-
/// This trait is essentially historical at this point. We maintain impls so
75-
/// that we have tested reference implementations. But these will eventually be
76-
/// migrated to `ReconfiguratorSpComponentUpdater` instead.
77-
pub trait SpComponentUpdater {
78-
/// The target component.
79-
///
80-
/// Should be produced via `SpComponent::const_as_str()`.
81-
fn component(&self) -> &'static str;
82-
83-
/// The type of the target SP.
84-
fn target_sp_type(&self) -> SpType;
85-
86-
/// The slot number of the target SP.
87-
fn target_sp_slot(&self) -> u16;
88-
89-
/// The target firmware slot for the component.
90-
fn firmware_slot(&self) -> u16;
91-
92-
/// The ID of this update.
93-
fn update_id(&self) -> Uuid;
94-
95-
/// The update payload data to send to MGS.
96-
// TODO-performance This has to be convertible into a `reqwest::Body`, so we
97-
// return an owned Vec. That requires all our implementors to clone the data
98-
// at least once; maybe we should use `Bytes` instead (which is cheap to
99-
// clone and also convertible into a reqwest::Body)?
100-
fn update_data(&self) -> Vec<u8>;
101-
102-
/// The sending half of the watch channel to report update progress.
103-
fn progress(&self) -> &watch::Sender<Option<UpdateProgress>>;
104-
105-
/// Logger to use while performing this update.
106-
fn logger(&self) -> &Logger;
107-
}
108-
109-
pub(super) async fn deliver_update(
110-
updater: &(dyn SpComponentUpdater + Send + Sync),
111-
mgs_clients: &mut MgsClients,
112-
) -> Result<(), SpComponentUpdateError> {
113-
// Start the update.
114-
mgs_clients
115-
.try_all_serially(updater.logger(), |client| async move {
116-
client
117-
.sp_component_update(
118-
updater.target_sp_type(),
119-
updater.target_sp_slot(),
120-
updater.component(),
121-
updater.firmware_slot(),
122-
&updater.update_id(),
123-
reqwest::Body::from(updater.update_data()),
124-
)
125-
.await?;
126-
updater.progress().send_replace(Some(UpdateProgress::Started));
127-
info!(
128-
updater.logger(), "update started";
129-
"mgs_addr" => client.baseurl(),
130-
);
131-
Ok::<_, GatewayClientError>(())
132-
})
133-
.await?;
134-
135-
// Wait for the update to complete.
136-
loop {
137-
let status = mgs_clients
138-
.try_all_serially(updater.logger(), |client| async move {
139-
let update_status = client
140-
.sp_component_update_status(
141-
updater.target_sp_type(),
142-
updater.target_sp_slot(),
143-
updater.component(),
144-
)
145-
.await?;
146-
147-
debug!(
148-
updater.logger(), "got update status";
149-
"mgs_addr" => client.baseurl(),
150-
"status" => ?update_status,
151-
);
152-
153-
Ok::<_, GatewayClientError>(update_status)
154-
})
155-
.await?;
156-
157-
if status_is_complete(
158-
status.into_inner(),
159-
updater.update_id(),
160-
updater.progress(),
161-
updater.logger(),
162-
)? {
163-
updater.progress().send_replace(Some(UpdateProgress::InProgress {
164-
progress: Some(1.0),
165-
}));
166-
return Ok(());
167-
}
168-
169-
tokio::time::sleep(STATUS_POLL_INTERVAL).await;
170-
}
171-
}
172-
173-
fn status_is_complete(
174-
status: SpUpdateStatus,
175-
update_id: Uuid,
176-
progress_tx: &watch::Sender<Option<UpdateProgress>>,
177-
log: &Logger,
178-
) -> Result<bool, SpComponentUpdateError> {
179-
match status {
180-
// For `Preparing` and `InProgress`, we could check the progress
181-
// information returned by these steps and try to check that
182-
// we're still _making_ progress, but every Nexus instance needs
183-
// to do that anyway in case we (or the MGS instance delivering
184-
// the update) crash, so we'll omit that check here. Instead, we
185-
// just sleep and we'll poll again shortly.
186-
SpUpdateStatus::Preparing { id, progress } => {
187-
if id == update_id {
188-
let progress = progress.and_then(|progress| {
189-
if progress.current > progress.total {
190-
warn!(
191-
log, "nonsense preparing progress";
192-
"current" => progress.current,
193-
"total" => progress.total,
194-
);
195-
None
196-
} else if progress.total == 0 {
197-
None
198-
} else {
199-
Some(
200-
f64::from(progress.current)
201-
/ f64::from(progress.total),
202-
)
203-
}
204-
});
205-
progress_tx
206-
.send_replace(Some(UpdateProgress::Preparing { progress }));
207-
Ok(false)
208-
} else {
209-
Err(SpComponentUpdateError::DifferentUpdatePreparing(id))
210-
}
211-
}
212-
SpUpdateStatus::InProgress { id, bytes_received, total_bytes } => {
213-
if id == update_id {
214-
let progress = if bytes_received > total_bytes {
215-
warn!(
216-
log, "nonsense update progress";
217-
"bytes_received" => bytes_received,
218-
"total_bytes" => total_bytes,
219-
);
220-
None
221-
} else if total_bytes == 0 {
222-
None
223-
} else {
224-
Some(f64::from(bytes_received) / f64::from(total_bytes))
225-
};
226-
progress_tx.send_replace(Some(UpdateProgress::InProgress {
227-
progress,
228-
}));
229-
Ok(false)
230-
} else {
231-
Err(SpComponentUpdateError::DifferentUpdateInProgress(id))
232-
}
233-
}
234-
SpUpdateStatus::Complete { id } => {
235-
if id == update_id {
236-
Ok(true)
237-
} else {
238-
Err(SpComponentUpdateError::DifferentUpdateComplete(id))
239-
}
240-
}
241-
SpUpdateStatus::None => Err(SpComponentUpdateError::UpdateStatusLost),
242-
SpUpdateStatus::Aborted { id } => {
243-
if id == update_id {
244-
Err(SpComponentUpdateError::UpdateAborted)
245-
} else {
246-
Err(SpComponentUpdateError::DifferentUpdateAborted(id))
247-
}
248-
}
249-
SpUpdateStatus::Failed { code, id } => {
250-
if id == update_id {
251-
Err(SpComponentUpdateError::UpdateFailedWithCode(code))
252-
} else {
253-
Err(SpComponentUpdateError::DifferentUpdateFailed(id))
254-
}
255-
}
256-
SpUpdateStatus::RotError { id, message } => {
257-
if id == update_id {
258-
Err(SpComponentUpdateError::UpdateFailedWithMessage(format!(
259-
"rot error: {message}"
260-
)))
261-
} else {
262-
Err(SpComponentUpdateError::DifferentUpdateFailed(id))
263-
}
264-
}
265-
}
266-
}
267-
26868
/// Implementors provide helper functions used while updating a particular SP
26969
/// component
27070
///

0 commit comments

Comments
 (0)