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
174 changes: 4 additions & 170 deletions nexus/reconfigurator/planning/src/mgs_updates/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@
//! Facilities for making choices about MGS-managed updates

mod rot;
mod sp;

use crate::mgs_updates::rot::RotUpdateState;
use crate::mgs_updates::rot::mgs_update_status_rot;
use crate::mgs_updates::rot::try_make_update_rot;
use crate::mgs_updates::sp::mgs_update_status_sp;
use crate::mgs_updates::sp::try_make_update_sp;

use gateway_types::rot::RotSlot;
use nexus_types::deployment::ExpectedActiveRotSlot;
Expand All @@ -21,14 +24,13 @@ use nexus_types::inventory::BaseboardId;
use nexus_types::inventory::CabooseWhich;
use nexus_types::inventory::Collection;
use omicron_common::api::external::TufRepoDescription;
use slog::{debug, error, info, warn};
use slog::{error, info, warn};
use slog_error_chain::InlineErrorChain;
use std::collections::BTreeSet;
use std::sync::Arc;
use thiserror::Error;
use tufaceous_artifact::ArtifactVersion;
use tufaceous_artifact::ArtifactVersionError;
use tufaceous_artifact::KnownArtifactKind;

/// How to handle an MGS-driven update that has become impossible due to
/// unsatisfied preconditions.
Expand Down Expand Up @@ -364,39 +366,6 @@ fn mgs_update_status(
}
}

/// Compares a configured SP update with information from inventory and
/// determines the current status of the update. See `MgsUpdateStatus`.
fn mgs_update_status_sp(
desired_version: &ArtifactVersion,
expected_active_version: &ArtifactVersion,
expected_inactive_version: &ExpectedVersion,
found_active_version: &str,
found_inactive_version: Option<&str>,
) -> MgsUpdateStatus {
if found_active_version == desired_version.as_str() {
// If we find the desired version in the active slot, we're done.
return MgsUpdateStatus::Done;
}

// The update hasn't completed.
//
// Check to make sure the contents of the active slot are still what they
// were when we configured this update. If not, then this update cannot
// proceed as currently configured. It will fail its precondition check.
if found_active_version != expected_active_version.as_str() {
return MgsUpdateStatus::Impossible;
}

// Similarly, check the contents of the inactive slot to determine if it
// still matches what we saw when we configured this update. If not, then
// this update cannot proceed as currently configured. It will fail its
// precondition check.
mgs_update_status_inactive_versions(
found_inactive_version,
expected_inactive_version,
)
}

fn mgs_update_status_inactive_versions(
found_inactive_version: Option<&str>,
expected_inactive_version: &ExpectedVersion,
Expand Down Expand Up @@ -464,141 +433,6 @@ fn try_make_update(
})
}

/// Determine if the given baseboard needs an SP update and, if so, returns it.
fn try_make_update_sp(
log: &slog::Logger,
baseboard_id: &Arc<BaseboardId>,
inventory: &Collection,
current_artifacts: &TufRepoDescription,
) -> Option<PendingMgsUpdate> {
let Some(sp_info) = inventory.sps.get(baseboard_id) else {
warn!(
log,
"cannot configure SP update for board \
(missing SP info from inventory)";
baseboard_id
);
return None;
};

let Some(active_caboose) =
inventory.caboose_for(CabooseWhich::SpSlot0, baseboard_id)
else {
warn!(
log,
"cannot configure SP update for board \
(missing active caboose from inventory)";
baseboard_id,
);
return None;
};

let Ok(expected_active_version) = active_caboose.caboose.version.parse()
else {
warn!(
log,
"cannot configure SP update for board \
(cannot parse current active version as an ArtifactVersion)";
baseboard_id,
"found_version" => &active_caboose.caboose.version,
);
return None;
};

let board = &active_caboose.caboose.board;
let matching_artifacts: Vec<_> = current_artifacts
.artifacts
.iter()
.filter(|a| {
// A matching SP artifact will have:
//
// - "name" matching the board name (found above from caboose)
// - "kind" matching one of the known SP kinds

if a.id.name != *board {
return false;
}

match a.id.kind.to_known() {
None => false,
Some(
KnownArtifactKind::GimletSp
| KnownArtifactKind::PscSp
| KnownArtifactKind::SwitchSp,
) => true,
Some(
KnownArtifactKind::GimletRot
| KnownArtifactKind::Host
| KnownArtifactKind::Trampoline
| KnownArtifactKind::InstallinatorDocument
| KnownArtifactKind::ControlPlane
| KnownArtifactKind::Zone
| KnownArtifactKind::PscRot
| KnownArtifactKind::SwitchRot
| KnownArtifactKind::GimletRotBootloader
| KnownArtifactKind::PscRotBootloader
| KnownArtifactKind::SwitchRotBootloader,
) => false,
}
})
.collect();
if matching_artifacts.is_empty() {
warn!(
log,
"cannot configure SP update for board (no matching artifact)";
baseboard_id,
);
return None;
}

if matching_artifacts.len() > 1 {
// This should be impossible unless we shipped a TUF repo with multiple
// artifacts for the same board. But it doesn't prevent us from picking
// one and proceeding. Make a note and proceed.
warn!(log, "found more than one matching artifact for SP update");
}

let artifact = matching_artifacts[0];

// If the artifact's version matches what's deployed, then no update is
// needed.
if artifact.id.version == expected_active_version {
debug!(log, "no SP update needed for board"; baseboard_id);
return None;
}

// Begin configuring an update.
let expected_inactive_version = match inventory
.caboose_for(CabooseWhich::SpSlot1, baseboard_id)
.map(|c| c.caboose.version.parse::<ArtifactVersion>())
.transpose()
{
Ok(None) => ExpectedVersion::NoValidVersion,
Ok(Some(v)) => ExpectedVersion::Version(v),
Err(_) => {
warn!(
log,
"cannot configure SP update for board \
(found inactive slot contents but version was not valid)";
baseboard_id
);
return None;
}
};

Some(PendingMgsUpdate {
baseboard_id: baseboard_id.clone(),
sp_type: sp_info.sp_type,
slot_id: sp_info.sp_slot,
details: PendingMgsUpdateDetails::Sp {
expected_active_version,
expected_inactive_version,
},
artifact_hash: artifact.hash,
artifact_version: artifact.id.version.clone(),
})
}

#[cfg(test)]
mod test {
use super::ImpossibleUpdatePolicy;
Expand Down
Loading
Loading