Skip to content

[reconfigurator] database support for PendingMgsUpdate for RoT #8588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from

Conversation

karencfv
Copy link
Contributor

@karencfv karencfv commented Jul 14, 2025

Equivalent of #8291 for RoT

Comment on lines +527 to +660
.baseboard_id
.serial_number
.clone()),
);
let count = diesel::insert_into(
update_dsl::bp_pending_mgs_update_sp,
)
.values(selection)
.into_columns((
update_dsl::blueprint_id,
update_dsl::hw_baseboard_id,
update_dsl::sp_type,
update_dsl::sp_slot,
update_dsl::artifact_sha256,
update_dsl::artifact_version,
update_dsl::expected_active_version,
update_dsl::expected_inactive_version,
))
.execute_async(&conn)
.await?;
if count != 1 {
// This should be impossible in practice. We
// will insert however many rows matched the
// `baseboard_id` parts of the query above. It
// can't be more than one 1 because we've
// filtered on a pair of columns that are unique
// together. It could only be 0 if the baseboard
// id had never been seen before in an inventory
// collection. But in that case, how did we
// manage to construct a blueprint with it?
//
// This could happen in the test suite or with
// `reconfigurator-cli`, which both let you
// create any blueprint you like. In the test
// suite, the test just has to deal with this
// behaviour (e.g., by inserting an inventory
// collection containing this SP). With
// `reconfigurator-cli`, this amounts to user
// error.
error!(&opctx.log,
"blueprint insertion: unexpectedly tried to \
insert wrong number of rows into \
bp_pending_mgs_update_sp (aborting transaction)";
"count" => count,
&update.baseboard_id,
);
return Err(TxnError::BadInsertCount {
table_name: "bp_pending_mgs_update_sp",
count,
baseboard_id: update.baseboard_id.clone(),
});
}
}
.into_sql::<Nullable<diesel::sql_types::Text>>();

// Skip formatting several lines to prevent rustfmt bailing
// out.
#[rustfmt::skip]
use nexus_db_schema::schema::hw_baseboard_id::dsl
as baseboard_dsl;
#[rustfmt::skip]
use nexus_db_schema::schema::bp_pending_mgs_update_sp::dsl
as update_dsl;
let selection =
nexus_db_schema::schema::hw_baseboard_id::table
.select((
db_blueprint_id,
baseboard_dsl::id,
db_sp_type,
db_slot_id,
db_artifact_hash,
db_artifact_version,
db_expected_version,
db_expected_inactive_version,
))
.filter(
baseboard_dsl::part_number.eq(update
.baseboard_id
.part_number
.clone()),
// This statement is just here to force a compilation
// error if the set of columns in
// `bp_pending_mgs_update_sp` changes because that
// will affect the correctness of the above
// statement.
//
// If you're here because of a compile error, you
// might be changing the `bp_pending_mgs_update_sp`
// table. Update the statement below and be sure to
// update the code above, too!
let (
_blueprint_id,
_hw_baseboard_id,
_sp_type,
_sp_slot,
_artifact_sha256,
_artifact_version,
_expected_active_version,
_expected_inactive_version,
) = update_dsl::bp_pending_mgs_update_sp::all_columns();
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is all a mechanical change, just moving everything SP related into the PendingMgsUpdateDetails::Sp arm, so I could do the same for RoT

Comment on lines +1416 to 1452
// Load all pending RoT updates.
//
// Pagination is a little silly here because we will only allow one at a
// time in practice for a while, but it's easy enough to do.
let mut pending_updates_rot = Vec::new();
{
use nexus_db_schema::schema::bp_pending_mgs_update_rot::dsl;

let mut paginator = Paginator::new(
SQL_BATCH_SIZE,
dropshot::PaginationOrder::Ascending,
);
while let Some(p) = paginator.next() {
let batch = paginated(
dsl::bp_pending_mgs_update_rot,
dsl::hw_baseboard_id,
&p.current_pagparams(),
)
.filter(dsl::blueprint_id.eq(to_db_typed_uuid(blueprint_id)))
.select(BpPendingMgsUpdateRot::as_select())
.load_async(&*conn)
.await
.map_err(|e| {
public_error_from_diesel(e, ErrorHandler::Server)
})?;

paginator = p.found_batch(&batch, &|d| d.hw_baseboard_id);
for row in batch {
pending_updates_rot.push(row);
}
}
}

// Load all pending SP updates.
let mut pending_updates_sp = Vec::new();
{
use nexus_db_schema::schema::bp_pending_mgs_update_sp::dsl;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We only allow one of PendingMgsUpdate at a time, so I think it should be OK to have these two one after the other in this manner.

Copy link
Contributor

Choose a reason for hiding this comment

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

I'd get a double check on this from someone else, maybe @jgallagher. Everything else looks great to me!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I'll be on stand-by then

Copy link
Contributor

Choose a reason for hiding this comment

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

Agreed, this looks fine!

Copy link
Contributor

@andrewjstone andrewjstone left a comment

Choose a reason for hiding this comment

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

Looks great!

Comment on lines +1416 to 1452
// Load all pending RoT updates.
//
// Pagination is a little silly here because we will only allow one at a
// time in practice for a while, but it's easy enough to do.
let mut pending_updates_rot = Vec::new();
{
use nexus_db_schema::schema::bp_pending_mgs_update_rot::dsl;

let mut paginator = Paginator::new(
SQL_BATCH_SIZE,
dropshot::PaginationOrder::Ascending,
);
while let Some(p) = paginator.next() {
let batch = paginated(
dsl::bp_pending_mgs_update_rot,
dsl::hw_baseboard_id,
&p.current_pagparams(),
)
.filter(dsl::blueprint_id.eq(to_db_typed_uuid(blueprint_id)))
.select(BpPendingMgsUpdateRot::as_select())
.load_async(&*conn)
.await
.map_err(|e| {
public_error_from_diesel(e, ErrorHandler::Server)
})?;

paginator = p.found_batch(&batch, &|d| d.hw_baseboard_id);
for row in batch {
pending_updates_rot.push(row);
}
}
}

// Load all pending SP updates.
let mut pending_updates_sp = Vec::new();
{
use nexus_db_schema::schema::bp_pending_mgs_update_sp::dsl;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd get a double check on this from someone else, maybe @jgallagher. Everything else looks great to me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants