-
Notifications
You must be signed in to change notification settings - Fork 46
[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
base: main
Are you sure you want to change the base?
Conversation
.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(); |
There was a problem hiding this comment.
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
// 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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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!
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, this looks fine!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great!
// 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; |
There was a problem hiding this comment.
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!
Equivalent of #8291 for RoT