Skip to content

[reconfigurator] RoT planner support #8421

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 33 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
f2e8de3
[reconfigurator] CLI support for setting RoT versions
karencfv Jun 23, 2025
fd098df
expectorate
karencfv Jun 24, 2025
799b169
planner support for configuring RoT update
karencfv Jun 25, 2025
914d4d5
set update hierarchy and clean up
karencfv Jun 25, 2025
3c7cc8b
Remove unnecessary todo
karencfv Jun 25, 2025
13c7934
Merge main
karencfv Jun 26, 2025
d9ca092
Add additional checks
karencfv Jun 26, 2025
7f8904e
clean up
karencfv Jun 26, 2025
6bee79f
Remove additional arguments
karencfv Jun 27, 2025
6e0f444
Add information to sled-show command
karencfv Jun 27, 2025
4827e16
clean up
karencfv Jun 27, 2025
e045766
clean up
karencfv Jun 27, 2025
3c4fe9f
merge main
karencfv Jul 9, 2025
f515fb7
fixes after merge
karencfv Jul 9, 2025
c44d9bf
address style comments
karencfv Jul 9, 2025
031a18f
fix target-release test
karencfv Jul 9, 2025
642fa92
Address comments
karencfv Jul 9, 2025
0434297
address comments
karencfv Jul 10, 2025
599589f
fmt
karencfv Jul 10, 2025
1ab8622
working test_basic
karencfv Jul 10, 2025
88702d0
Adapt sequential test
karencfv Jul 11, 2025
ce03cca
get all the tests passing
karencfv Jul 11, 2025
4f3b735
get all the tests passing
karencfv Jul 11, 2025
413ade6
clean up
karencfv Jul 11, 2025
6899baa
clean up
karencfv Jul 11, 2025
4013357
clippy and fmt
karencfv Jul 11, 2025
e6c655d
Merge main
karencfv Jul 16, 2025
4abbd8e
expectorate
karencfv Jul 16, 2025
91fea61
why did I change this in the first place?
karencfv Jul 17, 2025
370bceb
add some more tests
karencfv Jul 17, 2025
8cc29ae
merge main
karencfv Jul 22, 2025
cd9cea3
fixes after merging main
karencfv Jul 22, 2025
b71f5b8
small fixes
karencfv Jul 23, 2025
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
2 changes: 2 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions dev-tools/reconfigurator-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ iddqd.workspace = true
indent_write.workspace = true
internal-dns-types.workspace = true
itertools.workspace = true
gateway-types.workspace = true
newtype-uuid.workspace = true
nexus-inventory.workspace = true
nexus-reconfigurator-blippy.workspace = true
Expand Down
85 changes: 85 additions & 0 deletions dev-tools/reconfigurator-cli/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ fn process_command(
Commands::SledUpdateInstallDataset(args) => {
cmd_sled_update_install_dataset(sim, args)
}
Commands::SledUpdateRot(args) => cmd_sled_update_rot(sim, args),
Commands::SledUpdateSp(args) => cmd_sled_update_sp(sim, args),
Commands::SiloList => cmd_silo_list(sim),
Commands::SiloAdd(args) => cmd_silo_add(sim, args),
Expand Down Expand Up @@ -286,6 +287,8 @@ enum Commands {
SledSet(SledSetArgs),
/// update the install dataset on a sled, simulating a mupdate
SledUpdateInstallDataset(SledUpdateInstallDatasetArgs),
/// simulate updating the sled's RoT versions
SledUpdateRot(SledUpdateRotArgs),
/// simulate updating the sled's SP versions
SledUpdateSp(SledUpdateSpArgs),

Expand Down Expand Up @@ -504,6 +507,20 @@ struct SledUpdateSpArgs {
inactive: Option<ExpectedVersion>,
}

#[derive(Debug, Args)]
struct SledUpdateRotArgs {
/// id of the sled
sled_id: SledUuid,

/// sets the version reported for the RoT slot a
#[clap(long, required_unless_present_any = &["slot_b"])]
slot_a: Option<ExpectedVersion>,

/// sets the version reported for the RoT slot b
#[clap(long, required_unless_present_any = &["slot_a"])]
slot_b: Option<ExpectedVersion>,
}

#[derive(Debug, Args)]
struct SledSetMupdateOverrideArgs {
#[clap(flatten)]
Expand Down Expand Up @@ -1302,6 +1319,15 @@ fn cmd_sled_show(
let sled_id = args.sled_id.to_sled_id(description)?;
let sp_active_version = description.sled_sp_active_version(sled_id)?;
let sp_inactive_version = description.sled_sp_inactive_version(sled_id)?;
let rot_active_slot = description.sled_rot_active_slot(sled_id)?;
let rot_slot_a_version = description.sled_rot_slot_a_version(sled_id)?;
let rot_slot_b_version = description.sled_rot_slot_b_version(sled_id)?;
let rot_persistent_boot_preference =
description.sled_rot_persistent_boot_preference(sled_id)?;
let rot_pending_persistent_boot_preference =
description.sled_rot_pending_persistent_boot_preference(sled_id)?;
let rot_transient_boot_preference =
description.sled_rot_transient_boot_preference(sled_id)?;
let planning_input = description
.to_planning_input_builder()
.context("failed to generate planning_input builder")?
Expand All @@ -1314,6 +1340,24 @@ fn cmd_sled_show(
swriteln!(s, "subnet {}", sled_resources.subnet.net());
swriteln!(s, "SP active version: {:?}", sp_active_version);
swriteln!(s, "SP inactive version: {:?}", sp_inactive_version);
swriteln!(s, "RoT active slot: {}", rot_active_slot);
swriteln!(s, "RoT slot A version: {:?}", rot_slot_a_version);
swriteln!(s, "RoT slot B version: {:?}", rot_slot_b_version);
swriteln!(
s,
"RoT persistent boot preference: {}",
rot_persistent_boot_preference
);
swriteln!(
s,
"RoT pending persistent boot preference: {:?}",
rot_pending_persistent_boot_preference
);
swriteln!(
s,
"RoT transient boot preference: {:?}",
rot_transient_boot_preference
);
swriteln!(s, "zpools ({}):", sled_resources.zpools.len());
for (zpool, disk) in &sled_resources.zpools {
swriteln!(s, " {:?}", zpool);
Expand Down Expand Up @@ -1478,6 +1522,47 @@ fn cmd_sled_update_sp(
Ok(Some(format!("set sled {} SP versions: {}", sled_id, labels.join(", "))))
}

fn cmd_sled_update_rot(
sim: &mut ReconfiguratorSim,
args: SledUpdateRotArgs,
) -> anyhow::Result<Option<String>> {
let mut labels = Vec::new();

if let Some(slot_a) = &args.slot_a {
labels.push(format!("slot a -> {}", slot_a));
}
if let Some(slot_b) = &args.slot_b {
labels.push(format!("slot b -> {}", slot_b));
}

assert!(
!labels.is_empty(),
"clap configuration requires that at least one argument is specified"
);

let mut state = sim.current_state().to_mut();
state.system_mut().description_mut().sled_update_rot_versions(
args.sled_id,
args.slot_a,
args.slot_b,
)?;

sim.commit_and_bump(
format!(
"reconfigurator-cli sled-update-rot: {}: {}",
args.sled_id,
labels.join(", "),
),
state,
);

Ok(Some(format!(
"set sled {} RoT settings: {}",
args.sled_id,
labels.join(", ")
)))
}

fn cmd_inventory_list(
sim: &mut ReconfiguratorSim,
) -> anyhow::Result<Option<String>> {
Expand Down
57 changes: 44 additions & 13 deletions dev-tools/reconfigurator-cli/tests/input/cmds-target-release.txt
Original file line number Diff line number Diff line change
Expand Up @@ -31,44 +31,75 @@ sled-list
blueprint-list
inventory-list

# First step: upgrade one SP.
# First step: upgrade one RoT.
blueprint-plan dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 f45ba181-4b56-42cc-a762-874d90184a43
blueprint-diff dbcbd3d6-41ff-48ae-ac0b-1becc9b2fd21 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1

# If we generate another plan, there should be no change.
blueprint-plan 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1 f45ba181-4b56-42cc-a762-874d90184a43
blueprint-diff 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1 58d5e830-0884-47d8-a7cd-b2b3751adeb4

# Now, update the simulated SP to reflect that the update completed.
# Now, update the simulated RoT to reflect that the update completed.
# Collect inventory from it and use that collection for another planning step.
# This should report that the update completed, remove that update, and add one
# for another sled.
sled-update-sp 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6 --active 1.0.0
# for an SP on the same sled.
sled-update-rot 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6 --slot-a 1.0.0
inventory-generate
blueprint-plan 58d5e830-0884-47d8-a7cd-b2b3751adeb4 eb0796d5-ab8a-4f7b-a884-b4aeacb8ab51
blueprint-diff 58d5e830-0884-47d8-a7cd-b2b3751adeb4 af934083-59b5-4bf6-8966-6fb5292c29e1

# This time, make it more interesting. Change the inactive slot contents of
# the simulated SP. This should make the configured update impossible and cause
# the planner to fix it.
sled-update-sp 2b8f0cb3-0295-4b3c-bc58-4fe88b57112c --inactive 0.5.0
# After the RoT update has completed, we update the simulated SP to reflect that
# update has completed as well.
# Like before, collect inventory from it and use that collection for the next step.
# This should report that the update completed, remove that update, and add one
# for another sled.
sled-update-sp 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6 --active 1.0.0
inventory-generate
blueprint-plan af934083-59b5-4bf6-8966-6fb5292c29e1 61f451b3-2121-4ed6-91c7-a550054f6c21
blueprint-diff af934083-59b5-4bf6-8966-6fb5292c29e1 df06bb57-ad42-4431-9206-abff322896c7

# Now simulate the update completing successfully.
# Another planning step should try to update the last sled.
sled-update-sp 2b8f0cb3-0295-4b3c-bc58-4fe88b57112c --active 1.0.0
# This time, make it more interesting. Change the inactive slot contents of
# the simulated RoT. This should make the configured update impossible and cause
# the planner to fix it.
sled-update-rot 2b8f0cb3-0295-4b3c-bc58-4fe88b57112c --slot-b 0.5.0
inventory-generate
blueprint-plan df06bb57-ad42-4431-9206-abff322896c7 b1bda47d-2c19-4fba-96e3-d9df28db7436
blueprint-diff df06bb57-ad42-4431-9206-abff322896c7 7f976e0d-d2a5-4eeb-9e82-c82bc2824aba

# Now simulate the update completing successfully.
# Like before, we should see a pending SP update for this sled.
sled-update-rot 2b8f0cb3-0295-4b3c-bc58-4fe88b57112c --slot-a 1.0.0
inventory-generate
blueprint-plan 7f976e0d-d2a5-4eeb-9e82-c82bc2824aba a71f7a73-35a6-45e8-acbe-f1c5925eed69
blueprint-diff 7f976e0d-d2a5-4eeb-9e82-c82bc2824aba 9034c710-3e57-45f3-99e5-4316145e87ac

# Now we'll change the inactive slot contents of the simulated SP. Like with the
# RoT, this should make the update impossible and cause the planner to fix it.
sled-update-sp 2b8f0cb3-0295-4b3c-bc58-4fe88b57112c --inactive 0.5.0
inventory-generate
blueprint-plan 9034c710-3e57-45f3-99e5-4316145e87ac 0b5efbb3-0b1b-4bbf-b7d8-a2d6fca074c6
blueprint-diff 9034c710-3e57-45f3-99e5-4316145e87ac d60afc57-f15d-476c-bd0f-b1071e2bb976

# Let's simulate the successful SP update as well.
# Another couple of planning steps should try to update the last sled.
sled-update-sp 2b8f0cb3-0295-4b3c-bc58-4fe88b57112c --active 1.0.0
inventory-generate
blueprint-plan d60afc57-f15d-476c-bd0f-b1071e2bb976 78f72e8d-46a9-40a9-8618-602f54454d80
blueprint-diff d60afc57-f15d-476c-bd0f-b1071e2bb976 a5a8f242-ffa5-473c-8efd-2acf2dc0b736

# Update the RoT on the last sled.
# There should be one last pending SP update.
sled-update-rot d81c6a84-79b8-4958-ae41-ea46c9b19763 --slot-a 1.0.0
inventory-generate
blueprint-plan a5a8f242-ffa5-473c-8efd-2acf2dc0b736 39363465-89ae-4ac2-9be1-099068da9d45
blueprint-diff a5a8f242-ffa5-473c-8efd-2acf2dc0b736 626487fa-7139-45ec-8416-902271fc730b

# Finish updating the last sled and do one more planning run.
# This should update one control plane zone.
sled-update-sp d81c6a84-79b8-4958-ae41-ea46c9b19763 --active 1.0.0
inventory-generate
blueprint-plan 7f976e0d-d2a5-4eeb-9e82-c82bc2824aba a71f7a73-35a6-45e8-acbe-f1c5925eed69
blueprint-diff 7f976e0d-d2a5-4eeb-9e82-c82bc2824aba 9034c710-3e57-45f3-99e5-4316145e87ac
blueprint-plan 626487fa-7139-45ec-8416-902271fc730b 04bc9001-0836-4fec-b9cb-9d4760caf8b4
blueprint-diff 626487fa-7139-45ec-8416-902271fc730b c1a0d242-9160-40f4-96ae-61f8f40a0b1b

# We should continue walking through the update. We need to build out a
# reconfigurator-cli subcommand to simulate updated zone image sources (just
Expand Down
12 changes: 12 additions & 0 deletions dev-tools/reconfigurator-cli/tests/input/cmds.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,18 @@ sled-add 90c1102a-b9f5-4d88-92a2-60d54a2d98cc
sled-add 04ef3330-c682-4a08-8def-fcc4bef31bcd --policy non-provisionable
sled-list

sled-update-rot dde1c0e2-b10d-4621-b420-f179f7a7a00a
sled-update-rot dde1c0e2-b10d-4621-b420-f179f7a7a00a --slot-a 1.0.0
sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a
sled-update-rot dde1c0e2-b10d-4621-b420-f179f7a7a00a --slot-b 2.0.0
sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a
sled-update-rot dde1c0e2-b10d-4621-b420-f179f7a7a00a --slot-a 3.0.0
sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a
sled-update-rot dde1c0e2-b10d-4621-b420-f179f7a7a00a --slot-a 4.0.0 --slot-b invalid
sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a
sled-update-rot dde1c0e2-b10d-4621-b420-f179f7a7a00a --slot-a 4.0.0 --slot-b 5.0.0
sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a

sled-update-sp dde1c0e2-b10d-4621-b420-f179f7a7a00a
sled-update-sp dde1c0e2-b10d-4621-b420-f179f7a7a00a --active 1.0.0
sled-show dde1c0e2-b10d-4621-b420-f179f7a7a00a
Expand Down
27 changes: 21 additions & 6 deletions dev-tools/reconfigurator-cli/tests/output/cmds-example-stdout
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ serial serial1
subnet fd00:1122:3344:102::/64
SP active version: Some("0.0.1")
SP inactive version: None
RoT active slot: A
RoT slot A version: Some("0.0.2")
RoT slot B version: None
RoT persistent boot preference: A
RoT pending persistent boot preference: None
RoT transient boot preference: None
zpools (10):
055c4910-b641-46d9-b52d-313aae9d9cbf (zpool)
SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-055c4910-b641-46d9-b52d-313aae9d9cbf" }, disk_id: 6a0cb52f-5cc2-48a5-9f44-ac8dea3ac45b (physical_disk), policy: InService, state: Active }
Expand Down Expand Up @@ -427,6 +433,12 @@ serial serial0
subnet fd00:1122:3344:101::/64
SP active version: Some("0.0.1")
SP inactive version: None
RoT active slot: A
RoT slot A version: Some("0.0.2")
RoT slot B version: None
RoT persistent boot preference: A
RoT pending persistent boot preference: None
RoT transient boot preference: None
zpools (4):
0477165a-a72e-4814-b8d6-74aa02cb2040 (zpool)
SledDisk { disk_identity: DiskIdentity { vendor: "fake-vendor", model: "fake-model", serial: "serial-0477165a-a72e-4814-b8d6-74aa02cb2040" }, disk_id: 6a5a31ab-4edc-44e0-a7a1-4190bfe582f7 (physical_disk), policy: InService, state: Active }
Expand Down Expand Up @@ -1031,8 +1043,9 @@ Sled serial0
A 0101010101010101010101010101010101010101010101010101010101010101
B 0202020202020202020202020202020202020202020202020202020202020202
cabooses:
SLOT BOARD NAME VERSION GIT_COMMIT SIGN
SpSlot0 SimGimletSp SimGimletSp 0.0.1 unknown n/a
SLOT BOARD NAME VERSION GIT_COMMIT SIGN
SpSlot0 SimGimletSp SimGimletSp 0.0.1 unknown n/a
RotSlotA SimRot SimRot 0.0.2 unknown n/a
RoT pages:
SLOT DATA_BASE64
RoT: active slot: slot A
Expand All @@ -1053,8 +1066,9 @@ Sled serial1
A 0101010101010101010101010101010101010101010101010101010101010101
B 0202020202020202020202020202020202020202020202020202020202020202
cabooses:
SLOT BOARD NAME VERSION GIT_COMMIT SIGN
SpSlot0 SimGimletSp SimGimletSp 0.0.1 unknown n/a
SLOT BOARD NAME VERSION GIT_COMMIT SIGN
SpSlot0 SimGimletSp SimGimletSp 0.0.1 unknown n/a
RotSlotA SimRot SimRot 0.0.2 unknown n/a
RoT pages:
SLOT DATA_BASE64
RoT: active slot: slot A
Expand All @@ -1075,8 +1089,9 @@ Sled serial2
A 0101010101010101010101010101010101010101010101010101010101010101
B 0202020202020202020202020202020202020202020202020202020202020202
cabooses:
SLOT BOARD NAME VERSION GIT_COMMIT SIGN
SpSlot0 SimGimletSp SimGimletSp 0.0.1 unknown n/a
SLOT BOARD NAME VERSION GIT_COMMIT SIGN
SpSlot0 SimGimletSp SimGimletSp 0.0.1 unknown n/a
RotSlotA SimRot SimRot 0.0.2 unknown n/a
RoT pages:
SLOT DATA_BASE64
RoT: active slot: slot A
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ created repo-1.0.0.zip for system version 1.0.0
INFO extracting uploaded archive to <EXTRACTING_UPLOADED_ARCHIVE_TO_REDACTED>
INFO created directory to store extracted artifacts, path: <CREATED_DIRECTORY_TO_STORE_EXTRACTED_ARTIFACTS_PATH_REDACTED>
INFO added artifact, name: SimGimletSp, kind: gimlet_sp, version: 1.0.0, hash: 7e6667e646ad001b54c8365a3d309c03f89c59102723d38d01697ee8079fe670, length: 747
INFO added artifact, name: fake-gimlet-rot, kind: gimlet_rot_image_a, version: 1.0.0, hash: 04e4a7fdb84acca92c8fd3235e26d64ea61bef8a5f98202589fd346989c5720a, length: 735
INFO added artifact, name: fake-gimlet-rot, kind: gimlet_rot_image_b, version: 1.0.0, hash: 04e4a7fdb84acca92c8fd3235e26d64ea61bef8a5f98202589fd346989c5720a, length: 735
INFO added artifact, name: SimRot, kind: gimlet_rot_image_a, version: 1.0.0, hash: 04e4a7fdb84acca92c8fd3235e26d64ea61bef8a5f98202589fd346989c5720a, length: 735
INFO added artifact, name: SimRot, kind: gimlet_rot_image_b, version: 1.0.0, hash: 04e4a7fdb84acca92c8fd3235e26d64ea61bef8a5f98202589fd346989c5720a, length: 735
INFO added artifact, name: fake-gimlet-rot-bootloader, kind: gimlet_rot_bootloader, version: 1.0.0, hash: 005ea358f1cd316df42465b1e3a0334ea22cc0c0442cf9ddf9b42fbf49780236, length: 750
INFO added artifact, name: fake-host, kind: host_phase_1, version: 1.0.0, hash: 2053f8594971bbf0a7326c833e2ffc12b065b9d823b9c0b967d275fa595e4e89, length: 524288
INFO added artifact, name: fake-host, kind: host_phase_2, version: 1.0.0, hash: f3dd0c7a1bd4500ea0d8bcf67581f576d47752b2f1998a4cb0f0c3155c483008, length: 1048576
Expand Down
Loading
Loading