diff --git a/Cargo.lock b/Cargo.lock index a6ec05a8814..0d04305ff7d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6924,6 +6924,7 @@ dependencies = [ "expectorate", "gateway-client", "gateway-types", + "hex-literal", "id-map", "iddqd", "illumos-utils", diff --git a/dev-tools/reconfigurator-cli/tests/output/cmds-add-zones-with-mupdate-override-stdout b/dev-tools/reconfigurator-cli/tests/output/cmds-add-zones-with-mupdate-override-stdout index 1ee59db0ce8..040173296fc 100644 --- a/dev-tools/reconfigurator-cli/tests/output/cmds-add-zones-with-mupdate-override-stdout +++ b/dev-tools/reconfigurator-cli/tests/output/cmds-add-zones-with-mupdate-override-stdout @@ -194,7 +194,7 @@ to: blueprint 8da82a8e-bf97-4fbd-8ddd-9f6462732cf1 internal DNS: DNS zone: "control-plane.oxide.internal" (unchanged) - unchanged names: 51 (records: 65) + unchanged names: 52 (records: 68) external DNS: DNS zone: "oxide.example" (unchanged) @@ -255,7 +255,7 @@ to: blueprint 58d5e830-0884-47d8-a7cd-b2b3751adeb4 internal DNS: DNS zone: "control-plane.oxide.internal" (unchanged) - unchanged names: 51 (records: 65) + unchanged names: 52 (records: 68) external DNS: DNS zone: "oxide.example" (unchanged) @@ -386,6 +386,14 @@ internal DNS: * DNS zone: "control-plane.oxide.internal": + name: 571a8adf-f0b8-458c-8e6c-5a71e82af7ae.host (records: 1) + AAAA fd00:1122:3344:103::28 +* name: _nexus-lockstep._tcp (records: 3 -> 4) +- SRV port 12232 0c71b3b2-6ceb-4e8f-b020-b08675e83038.host.control-plane.oxide.internal +- SRV port 12232 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6.host.control-plane.oxide.internal +- SRV port 12232 466a9f29-62bf-4e63-924a-b9efdb86afec.host.control-plane.oxide.internal ++ SRV port 12232 0c71b3b2-6ceb-4e8f-b020-b08675e83038.host.control-plane.oxide.internal ++ SRV port 12232 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6.host.control-plane.oxide.internal ++ SRV port 12232 466a9f29-62bf-4e63-924a-b9efdb86afec.host.control-plane.oxide.internal ++ SRV port 12232 571a8adf-f0b8-458c-8e6c-5a71e82af7ae.host.control-plane.oxide.internal * name: _nexus._tcp (records: 3 -> 4) - SRV port 12221 0c71b3b2-6ceb-4e8f-b020-b08675e83038.host.control-plane.oxide.internal - SRV port 12221 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6.host.control-plane.oxide.internal diff --git a/dev-tools/reconfigurator-cli/tests/output/cmds-mupdate-update-flow-stdout b/dev-tools/reconfigurator-cli/tests/output/cmds-mupdate-update-flow-stdout index cb8b7f81cfb..51ac8e590b6 100644 --- a/dev-tools/reconfigurator-cli/tests/output/cmds-mupdate-update-flow-stdout +++ b/dev-tools/reconfigurator-cli/tests/output/cmds-mupdate-update-flow-stdout @@ -1813,7 +1813,7 @@ planning report: * 1 pending MGS update: * model0:serial0: RotBootloader(PendingMgsUpdateRotBootloaderDetails { expected_stage0_version: ArtifactVersion("0.0.1"), expected_stage0_next_version: NoValidVersion }) * only placed 0/1 desired nexus zones -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1998,7 +1998,7 @@ planning report: * 1 pending MGS update: * model0:serial0: RotBootloader(PendingMgsUpdateRotBootloaderDetails { expected_stage0_version: ArtifactVersion("0.0.1"), expected_stage0_next_version: NoValidVersion }) * only placed 0/1 desired nexus zones -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2171,9 +2171,9 @@ INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noo INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 6, num_already_artifact: 6, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO MGS-driven update completed (will remove it and re-evaluate board), artifact_version: 2.0.0, artifact_hash: 8f89bf8bc5f3271650ad72a26fc0d116c910161ca143731473a2b20fb82653cc, expected_stage0_next_version: NoValidVersion, expected_stage0_version: 0.0.1, component: rot_bootloader, sp_slot: 0, sp_type: Sled, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update INFO some zones not yet up-to-date, zones_currently_updating: [ZonePropagationIncomplete { zone_id: 353b3b65-20f7-48c3-88f7-495bd5d31545 (service), zone_kind: Clickhouse, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("bb2d1ff02d11f72bc9049ae57f27536207519a1859d29f8d7a90ab3b44d56b08") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 466a9f29-62bf-4e63-924a-b9efdb86afec (service), zone_kind: Nexus, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("e9b7035f41848a987a798c15ac424cc91dd662b1af0920d58d8aa1ebad7467b6") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 62620961-fc4a-481e-968b-f5acbac0dc63 (service), zone_kind: InternalNtp, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("d76e26198daed69cdae04490d7477f8c842e0dbe37d463eac0d0a8d3fb803095") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 6c3ae381-04f7-41ea-b0ac-74db387dbc3a (service), zone_kind: ExternalDns, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("f282c45771429f7bebf71f0cc668521066db57c6bb07fcfccdfb44825d3d930f") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 99e2f30b-3174-40bf-a78a-90da8abba8ca (service), zone_kind: InternalDns, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("de30657a72b066b8ef1f56351a0a5d4d7000da0a62c4be9b2e949a107ca8a389") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: ad6a3a03-8d0f-4504-99a4-cbf73d69b973 (service), zone_kind: CruciblePantry, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("3ff26dad96faa8f67251f5de40458b4f809d536bfe8572134da0e42c2fa12674") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: bd354eef-d8a6-4165-9124-283fb5e46d77 (service), zone_kind: Crucible, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("866f6a7c2e51c056fb722b5113e80181cc9cd8b712a0d3dbf1edc4ce29e5229e") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 0c71b3b2-6ceb-4e8f-b020-b08675e83038 (service), zone_kind: Nexus, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("0e32b4a3e5d3668bb1d6a16fb06b74dc60b973fa479dcee0aae3adbb52bf1388") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 427ec88f-f467-42fa-9bbb-66a91a36103c (service), zone_kind: InternalDns, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("ffbf1373f7ee08dddd74c53ed2a94e7c4c572a982d3a9bc94000c6956b700c6a") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 5199c033-4cf9-4ab6-8ae7-566bd7606363 (service), zone_kind: Crucible, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("6f17cf65fb5a5bec5542dd07c03cd0acc01e59130f02c532c8d848ecae810047") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 6444f8a5-6465-4f0b-a549-1993c113569c (service), zone_kind: InternalNtp, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("67593d686ed04a1709f93972b71f4ebc148a9362120f65d239943e814a9a7439") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 803bfb63-c246-41db-b0da-d3b87ddfc63d (service), zone_kind: ExternalDns, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("ccca13ed19b8731f9adaf0d6203b02ea3b9ede4fa426b9fac0a07ce95440046d") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: ba4994a8-23f9-4b1a-a84f-a08d74591389 (service), zone_kind: CruciblePantry, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("21f0ada306859c23917361f2e0b9235806c32607ec689c7e8cf16bb898bc5a02") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6 (service), zone_kind: Nexus, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("e9b7035f41848a987a798c15ac424cc91dd662b1af0920d58d8aa1ebad7467b6") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: 75b220ba-a0f4-4872-8202-dc7c87f062d0 (service), zone_kind: CruciblePantry, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("3ff26dad96faa8f67251f5de40458b4f809d536bfe8572134da0e42c2fa12674") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: ea5b4030-b52f-44b2-8d70-45f15f987d01 (service), zone_kind: InternalDns, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("de30657a72b066b8ef1f56351a0a5d4d7000da0a62c4be9b2e949a107ca8a389") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: f10a4fb9-759f-4a65-b25e-5794ad2d07d8 (service), zone_kind: InternalNtp, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("d76e26198daed69cdae04490d7477f8c842e0dbe37d463eac0d0a8d3fb803095") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: f55647d4-5500-4ad3-893a-df45bd50d622 (service), zone_kind: Crucible, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("866f6a7c2e51c056fb722b5113e80181cc9cd8b712a0d3dbf1edc4ce29e5229e") }, inv_image_source: InstallDataset } }, ZonePropagationIncomplete { zone_id: f6ec9c67-946a-4da3-98d5-581f72ce8bf0 (service), zone_kind: ExternalDns, reason: ImageSourceMismatch { bp_image_source: Artifact { version: Available { version: ArtifactVersion("2.0.0") }, hash: ArtifactHash("f282c45771429f7bebf71f0cc668521066db57c6bb07fcfccdfb44825d3d930f") }, inv_image_source: InstallDataset } }] generated blueprint 61a93ea3-c872-48e0-aace-e86b0c52b839 based on parent blueprint 12d602a6-5ab4-487a-b94e-eb30cdf30300 diff --git a/dev-tools/reconfigurator-cli/tests/output/cmds-target-release-stdout b/dev-tools/reconfigurator-cli/tests/output/cmds-target-release-stdout index b9b99c77fce..f8f9dc5cf6f 100644 --- a/dev-tools/reconfigurator-cli/tests/output/cmds-target-release-stdout +++ b/dev-tools/reconfigurator-cli/tests/output/cmds-target-release-stdout @@ -148,7 +148,7 @@ planning report: * noop converting 8/8 install-dataset zones to artifact store on sled d81c6a84-79b8-4958-ae41-ea46c9b19763 * 1 pending MGS update: * model0:serial0: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: A, version: ArtifactVersion("0.0.2") }, expected_inactive_version: NoValidVersion, expected_persistent_boot_preference: A, expected_pending_persistent_boot_preference: None, expected_transient_boot_preference: None }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) @@ -1121,7 +1121,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: RotBootloader(PendingMgsUpdateRotBootloaderDetails { expected_stage0_version: ArtifactVersion("0.0.1"), expected_stage0_next_version: NoValidVersion }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1185,7 +1185,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: RotBootloader(PendingMgsUpdateRotBootloaderDetails { expected_stage0_version: ArtifactVersion("0.0.1"), expected_stage0_next_version: NoValidVersion }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1251,7 +1251,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: A, version: ArtifactVersion("0.0.2") }, expected_inactive_version: NoValidVersion, expected_persistent_boot_preference: A, expected_pending_persistent_boot_preference: None, expected_transient_boot_preference: None }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1326,7 +1326,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: Sp(PendingMgsUpdateSpDetails { expected_active_version: ArtifactVersion("0.0.1"), expected_inactive_version: NoValidVersion }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1402,7 +1402,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: HostPhase1(PendingMgsUpdateHostPhase1Details { expected_active_phase_1_slot: A, expected_boot_disk: A, expected_active_phase_1_hash: ArtifactHash("0101010101010101010101010101010101010101010101010101010101010101"), expected_active_phase_2_hash: ArtifactHash("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), expected_inactive_phase_1_hash: ArtifactHash("0202020202020202020202020202020202020202020202020202020202020202"), expected_inactive_phase_2_hash: ArtifactHash("d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47"), sled_agent_address: [fd00:1122:3344:101::1]:12345 }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1527,7 +1527,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: HostPhase1(PendingMgsUpdateHostPhase1Details { expected_active_phase_1_slot: A, expected_boot_disk: A, expected_active_phase_1_hash: ArtifactHash("0101010101010101010101010101010101010101010101010101010101010101"), expected_active_phase_2_hash: ArtifactHash("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), expected_inactive_phase_1_hash: ArtifactHash("0202020202020202020202020202020202020202020202020202020202020202"), expected_inactive_phase_2_hash: ArtifactHash("d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47"), sled_agent_address: [fd00:1122:3344:101::1]:12345 }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1592,7 +1592,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: HostPhase1(PendingMgsUpdateHostPhase1Details { expected_active_phase_1_slot: A, expected_boot_disk: A, expected_active_phase_1_hash: ArtifactHash("0101010101010101010101010101010101010101010101010101010101010101"), expected_active_phase_2_hash: ArtifactHash("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), expected_inactive_phase_1_hash: ArtifactHash("0202020202020202020202020202020202020202020202020202020202020202"), expected_inactive_phase_2_hash: ArtifactHash("d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47"), sled_agent_address: [fd00:1122:3344:101::1]:12345 }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1656,7 +1656,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model0:serial0: HostPhase1(PendingMgsUpdateHostPhase1Details { expected_active_phase_1_slot: A, expected_boot_disk: A, expected_active_phase_1_hash: ArtifactHash("0101010101010101010101010101010101010101010101010101010101010101"), expected_active_phase_2_hash: ArtifactHash("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), expected_inactive_phase_1_hash: ArtifactHash("0202020202020202020202020202020202020202020202020202020202020202"), expected_inactive_phase_2_hash: ArtifactHash("d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47"), sled_agent_address: [fd00:1122:3344:101::1]:12345 }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1711,7 +1711,7 @@ INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-495 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: b, expected_hash: 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b INFO MGS-driven update completed (will remove it and re-evaluate board), artifact_version: 1.0.0, artifact_hash: b99d5273ba1418bebb19d74b701d716896409566d41de76ada71bded4c9b166b, sled_agent_address: [fd00:1122:3344:101::1]:12345, expected_inactive_phase_2_hash: d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47, expected_inactive_phase_1_hash: 0202020202020202020202020202020202020202020202020202020202020202, expected_active_phase_2_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a, expected_active_phase_1_hash: 0101010101010101010101010101010101010101010101010101010101010101, expected_boot_disk: A, expected_active_phase_1_slot: A, component: host_phase_1, sp_slot: 0, sp_type: Sled, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 INFO configuring MGS-driven update, artifact_version: 1.0.0, artifact_hash: 5b0f601b1fbb8674db9c751a02f8b14f8e6d4e8470f4f7b686fecb2c49ec11f9, expected_stage0_next_version: NoValidVersion, expected_stage0_version: 0.0.1, component: rot_bootloader, sp_slot: 1, sp_type: Sled, serial_number: serial1, part_number: model1 INFO reached maximum number of pending MGS-driven updates, max: 1 generated blueprint afb09faf-a586-4483-9289-04d4f1d8ba23 based on parent blueprint c1a0d242-9160-40f4-96ae-61f8f40a0b1b @@ -1722,7 +1722,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: RotBootloader(PendingMgsUpdateRotBootloaderDetails { expected_stage0_version: ArtifactVersion("0.0.1"), expected_stage0_next_version: NoValidVersion }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1799,7 +1799,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: RotBootloader(PendingMgsUpdateRotBootloaderDetails { expected_stage0_version: ArtifactVersion("0.0.1"), expected_stage0_next_version: Version(ArtifactVersion("0.5.0")) }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1871,7 +1871,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: A, version: ArtifactVersion("0.0.2") }, expected_inactive_version: NoValidVersion, expected_persistent_boot_preference: A, expected_pending_persistent_boot_preference: None, expected_transient_boot_preference: None }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -1947,7 +1947,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: A, version: ArtifactVersion("0.0.2") }, expected_inactive_version: Version(ArtifactVersion("0.5.0")), expected_persistent_boot_preference: A, expected_pending_persistent_boot_preference: None, expected_transient_boot_preference: None }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2019,7 +2019,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: Sp(PendingMgsUpdateSpDetails { expected_active_version: ArtifactVersion("0.0.1"), expected_inactive_version: NoValidVersion }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2094,7 +2094,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: Sp(PendingMgsUpdateSpDetails { expected_active_version: ArtifactVersion("0.0.1"), expected_inactive_version: Version(ArtifactVersion("0.5.0")) }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2167,7 +2167,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: HostPhase1(PendingMgsUpdateHostPhase1Details { expected_active_phase_1_slot: A, expected_boot_disk: A, expected_active_phase_1_hash: ArtifactHash("0101010101010101010101010101010101010101010101010101010101010101"), expected_active_phase_2_hash: ArtifactHash("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), expected_inactive_phase_1_hash: ArtifactHash("0202020202020202020202020202020202020202020202020202020202020202"), expected_inactive_phase_2_hash: ArtifactHash("d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47"), sled_agent_address: [fd00:1122:3344:102::1]:12345 }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2307,7 +2307,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model1:serial1: HostPhase1(PendingMgsUpdateHostPhase1Details { expected_active_phase_1_slot: A, expected_boot_disk: A, expected_active_phase_1_hash: ArtifactHash("0101010101010101010101010101010101010101010101010101010101010101"), expected_active_phase_2_hash: ArtifactHash("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), expected_inactive_phase_1_hash: ArtifactHash("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"), expected_inactive_phase_2_hash: ArtifactHash("d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47"), sled_agent_address: [fd00:1122:3344:102::1]:12345 }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2373,8 +2373,8 @@ INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-495 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: b, expected_hash: 0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b INFO MGS-driven update completed (will remove it and re-evaluate board), artifact_version: 1.0.0, artifact_hash: b99d5273ba1418bebb19d74b701d716896409566d41de76ada71bded4c9b166b, sled_agent_address: [fd00:1122:3344:102::1]:12345, expected_inactive_phase_2_hash: d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47, expected_inactive_phase_1_hash: ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff, expected_active_phase_2_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a, expected_active_phase_1_hash: 0101010101010101010101010101010101010101010101010101010101010101, expected_boot_disk: A, expected_active_phase_1_slot: A, component: host_phase_1, sp_slot: 1, sp_type: Sled, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 INFO configuring MGS-driven update, artifact_version: 1.0.0, artifact_hash: 5b0f601b1fbb8674db9c751a02f8b14f8e6d4e8470f4f7b686fecb2c49ec11f9, expected_stage0_next_version: NoValidVersion, expected_stage0_version: 0.0.1, component: rot_bootloader, sp_slot: 2, sp_type: Sled, serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 13cfdd24-52ba-4e94-8c83-02e3a48fc746 based on parent blueprint 9a9e6c32-5a84-4020-a159-33dceff18d35 @@ -2385,7 +2385,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model2:serial2: RotBootloader(PendingMgsUpdateRotBootloaderDetails { expected_stage0_version: ArtifactVersion("0.0.1"), expected_stage0_next_version: NoValidVersion }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2456,7 +2456,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model2:serial2: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: A, version: ArtifactVersion("0.0.2") }, expected_inactive_version: NoValidVersion, expected_persistent_boot_preference: A, expected_pending_persistent_boot_preference: None, expected_transient_boot_preference: None }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2531,7 +2531,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model2:serial2: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: A, version: ArtifactVersion("0.0.2") }, expected_inactive_version: Version(ArtifactVersion("1.0.0")), expected_persistent_boot_preference: B, expected_pending_persistent_boot_preference: None, expected_transient_boot_preference: None }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2608,7 +2608,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model2:serial2: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: B, version: ArtifactVersion("1.1.0") }, expected_inactive_version: Version(ArtifactVersion("0.0.2")), expected_persistent_boot_preference: B, expected_pending_persistent_boot_preference: Some(B), expected_transient_boot_preference: None }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2682,7 +2682,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model2:serial2: Rot(PendingMgsUpdateRotDetails { expected_active_slot: ExpectedActiveRotSlot { slot: B, version: ArtifactVersion("1.1.0") }, expected_inactive_version: Version(ArtifactVersion("0.0.2")), expected_persistent_boot_preference: B, expected_pending_persistent_boot_preference: None, expected_transient_boot_preference: Some(B) }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2754,7 +2754,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model2:serial2: Sp(PendingMgsUpdateSpDetails { expected_active_version: ArtifactVersion("0.0.1"), expected_inactive_version: NoValidVersion }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2825,7 +2825,7 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 8 zones are already from artifacts * 1 pending MGS update: * model2:serial2: HostPhase1(PendingMgsUpdateHostPhase1Details { expected_active_phase_1_slot: A, expected_boot_disk: A, expected_active_phase_1_hash: ArtifactHash("0101010101010101010101010101010101010101010101010101010101010101"), expected_active_phase_2_hash: ArtifactHash("0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a"), expected_inactive_phase_1_hash: ArtifactHash("0202020202020202020202020202020202020202020202020202020202020202"), expected_inactive_phase_2_hash: ArtifactHash("d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47"), sled_agent_address: [fd00:1122:3344:103::1]:12345 }) -* zone updates waiting on pending MGS updates (RoT / SP / Host OS / etc.) +* zone updates waiting on pending MGS updates (RoT bootloader / RoT / SP / Host OS) * waiting to update top-level nexus_generation: some non-Nexus zone are not yet updated @@ -2950,9 +2950,9 @@ INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noo INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO MGS-driven update completed (will remove it and re-evaluate board), artifact_version: 1.0.0, artifact_hash: b99d5273ba1418bebb19d74b701d716896409566d41de76ada71bded4c9b166b, sled_agent_address: [fd00:1122:3344:103::1]:12345, expected_inactive_phase_2_hash: d944ae205b61ccf4322448f7d0311a819c53d9844769de066c5307c1682abb47, expected_inactive_phase_1_hash: 0202020202020202020202020202020202020202020202020202020202020202, expected_active_phase_2_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a, expected_active_phase_1_hash: 0101010101010101010101010101010101010101010101010101010101010101, expected_boot_disk: A, expected_active_phase_1_slot: A, component: host_phase_1, sp_slot: 2, sp_type: Sled, serial_number: serial2, part_number: model2 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 INFO ran out of boards for MGS-driven update generated blueprint b2295597-5788-482e-acf9-1731ec63fbd2 based on parent blueprint 459a45a5-616e-421f-873b-2fb08c36205c blueprint source: planner with report: @@ -3084,9 +3084,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 6fad8fd4-e825-433f-b76d-495484e068ce based on parent blueprint b2295597-5788-482e-acf9-1731ec63fbd2 blueprint source: planner with report: @@ -3223,9 +3223,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update INFO some zones not yet up-to-date, zones_currently_updating: [ZonePropagationIncomplete { zone_id: ba87399e-e9b7-4ee4-8cb7-0032822630e9 (service), zone_kind: InternalNtp, reason: MissingInInventory { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("67593d686ed04a1709f93972b71f4ebc148a9362120f65d239943e814a9a7439") } } }] generated blueprint 24b6e243-100c-428d-8ea6-35b504226f55 based on parent blueprint 6fad8fd4-e825-433f-b76d-495484e068ce @@ -3359,9 +3359,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 79fff7a2-2495-4c75-8465-4dc01bab48ce based on parent blueprint 24b6e243-100c-428d-8ea6-35b504226f55 blueprint source: planner with report: @@ -3509,9 +3509,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 3bcc37b2-0c0b-44d0-b4ed-3bcb605e4312 based on parent blueprint 79fff7a2-2495-4c75-8465-4dc01bab48ce blueprint source: planner with report: @@ -3660,9 +3660,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 4d2eb6f3-7eb1-443a-8e76-7ecf05da2f6d based on parent blueprint 3bcc37b2-0c0b-44d0-b4ed-3bcb605e4312 blueprint source: planner with report: @@ -3789,9 +3789,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint e2125c83-b255-45c9-bc9b-802cff09a812 based on parent blueprint 4d2eb6f3-7eb1-443a-8e76-7ecf05da2f6d blueprint source: planner with report: @@ -3942,9 +3942,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint f4a6848e-d13c-46e1-8c6a-944f886d7ba3 based on parent blueprint e2125c83-b255-45c9-bc9b-802cff09a812 blueprint source: planner with report: @@ -4096,9 +4096,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 834e4dbe-3b71-443d-bd4c-20e8253abc0c based on parent blueprint f4a6848e-d13c-46e1-8c6a-944f886d7ba3 blueprint source: planner with report: @@ -4237,9 +4237,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint d9c5c5e3-c532-4c45-9ef5-22cb00f6a2e1 based on parent blueprint 834e4dbe-3b71-443d-bd4c-20e8253abc0c blueprint source: planner with report: @@ -4379,9 +4379,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint e2deb7c0-2262-49fe-855f-4250c22afb36 based on parent blueprint d9c5c5e3-c532-4c45-9ef5-22cb00f6a2e1 blueprint source: planner with report: @@ -4513,9 +4513,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 23ce505c-8991-44a5-8863-f2b906fba9cf based on parent blueprint e2deb7c0-2262-49fe-855f-4250c22afb36 blueprint source: planner with report: @@ -4650,9 +4650,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint c0d81ea6-909c-4efb-964e-beff67f6da0d based on parent blueprint 23ce505c-8991-44a5-8863-f2b906fba9cf blueprint source: planner with report: @@ -4772,9 +4772,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 60b55d33-5fec-4277-9864-935197eaead7 based on parent blueprint c0d81ea6-909c-4efb-964e-beff67f6da0d blueprint source: planner with report: @@ -4914,9 +4914,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint aa13f40f-41ff-4b68-bee1-df2e1f805544 based on parent blueprint 60b55d33-5fec-4277-9864-935197eaead7 blueprint source: planner with report: @@ -5057,9 +5057,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 316ccd9e-5c53-46c3-a2e9-20c3867b7111 based on parent blueprint aa13f40f-41ff-4b68-bee1-df2e1f805544 blueprint source: planner with report: @@ -5181,9 +5181,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 02078c95-3d58-4b7b-a03f-9b160361c50a based on parent blueprint 316ccd9e-5c53-46c3-a2e9-20c3867b7111 blueprint source: planner with report: @@ -5314,9 +5314,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update INFO some zones not yet up-to-date, zones_currently_updating: [ZonePropagationIncomplete { zone_id: e14f91b0-0c41-48a0-919d-e5078d2b89b0 (service), zone_kind: InternalNtp, reason: MissingInInventory { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("67593d686ed04a1709f93972b71f4ebc148a9362120f65d239943e814a9a7439") } } }] generated blueprint e7a01ffc-6b0e-408b-917b-b1efe18b3110 based on parent blueprint 02078c95-3d58-4b7b-a03f-9b160361c50a @@ -5450,9 +5450,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 880e2ffc-8187-4275-a2f3-1b36aa2f4482 based on parent blueprint e7a01ffc-6b0e-408b-917b-b1efe18b3110 blueprint source: planner with report: @@ -5597,9 +5597,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint c4a20bcb-1a71-4e88-97b4-36d16f55daec based on parent blueprint 880e2ffc-8187-4275-a2f3-1b36aa2f4482 blueprint source: planner with report: @@ -5745,9 +5745,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint a2c6496d-98fc-444d-aa36-99508aa72367 based on parent blueprint c4a20bcb-1a71-4e88-97b4-36d16f55daec blueprint source: planner with report: @@ -5883,9 +5883,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 6ed56354-5941-40d1-a06c-b0e940701d52 based on parent blueprint a2c6496d-98fc-444d-aa36-99508aa72367 blueprint source: planner with report: @@ -6022,9 +6022,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 9078c4ba-3a73-4b3f-ac2c-acb501f89cb2 based on parent blueprint 6ed56354-5941-40d1-a06c-b0e940701d52 blueprint source: planner with report: @@ -6156,9 +6156,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 8763abc1-8a42-4932-b5a7-33109e0e0152 based on parent blueprint 9078c4ba-3a73-4b3f-ac2c-acb501f89cb2 blueprint source: planner with report: @@ -6278,9 +6278,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 2b89e0d7-f15b-4474-8ac4-85959ed1bc88 based on parent blueprint 8763abc1-8a42-4932-b5a7-33109e0e0152 blueprint source: planner with report: @@ -6408,9 +6408,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 7, num_already_artifact: 7, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 7f6b7297-c2bc-4f67-b3c0-c8e555ebbdc4 based on parent blueprint 2b89e0d7-f15b-4474-8ac4-85959ed1bc88 blueprint source: planner with report: @@ -6539,9 +6539,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 59630e63-c953-4807-9e84-9e750a79f68e based on parent blueprint 7f6b7297-c2bc-4f67-b3c0-c8e555ebbdc4 blueprint source: planner with report: @@ -6662,9 +6662,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint e93650dc-b5ba-4ec7-8550-9171c1ada194 based on parent blueprint 59630e63-c953-4807-9e84-9e750a79f68e blueprint source: planner with report: @@ -6803,9 +6803,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 7, num_already_artifact: 7, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 90650737-8142-47a6-9a48-a10efc487e57 based on parent blueprint e93650dc-b5ba-4ec7-8550-9171c1ada194 blueprint source: planner with report: @@ -6945,9 +6945,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 2182613d-dc9f-41eb-9c6a-d33801849caa based on parent blueprint 90650737-8142-47a6-9a48-a10efc487e57 blueprint source: planner with report: @@ -7080,9 +7080,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 7, num_already_artifact: 7, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update INFO some zones not yet up-to-date, zones_currently_updating: [ZonePropagationIncomplete { zone_id: 9e2e0774-3cf6-4f75-9a12-92db05c77b81 (service), zone_kind: InternalNtp, reason: MissingInInventory { bp_image_source: Artifact { version: Available { version: ArtifactVersion("1.0.0") }, hash: ArtifactHash("67593d686ed04a1709f93972b71f4ebc148a9362120f65d239943e814a9a7439") } } }] generated blueprint e8b088a8-7da0-480b-a2dc-75ffef068ece based on parent blueprint 2182613d-dc9f-41eb-9c6a-d33801849caa @@ -7218,9 +7218,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 810ea95a-4730-43dd-867e-1984aeb9d873 based on parent blueprint e8b088a8-7da0-480b-a2dc-75ffef068ece blueprint source: planner with report: @@ -7346,9 +7346,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 67c074ef-c52e-4ff1-851a-598c04dc2c8d based on parent blueprint 810ea95a-4730-43dd-867e-1984aeb9d873 blueprint source: planner with report: @@ -7492,9 +7492,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 7, num_already_artifact: 7, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 0a8d2f87-1d3e-4296-ba07-108940a7a57e based on parent blueprint 67c074ef-c52e-4ff1-851a-598c04dc2c8d blueprint source: planner with report: @@ -7642,9 +7642,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint d69e1109-06be-4469-8876-4292dc7885d7 based on parent blueprint 0a8d2f87-1d3e-4296-ba07-108940a7a57e blueprint source: planner with report: @@ -7932,9 +7932,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 9, num_already_artifact: 9, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 12f19448-6a10-4b4b-ae19-a8c94a566097 based on parent blueprint d69e1109-06be-4469-8876-4292dc7885d7 blueprint source: planner with report: @@ -8023,9 +8023,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 9, num_already_artifact: 9, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 4713f6c4-e8ba-4a28-87a0-df75ebf7b8b6 based on parent blueprint 12f19448-6a10-4b4b-ae19-a8c94a566097 blueprint source: planner with report: @@ -8084,9 +8084,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 9, num_already_artifact: 9, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 6d830d26-547e-492b-adfe-c5c4ad9c3751 based on parent blueprint 4713f6c4-e8ba-4a28-87a0-df75ebf7b8b6 blueprint source: planner with report: @@ -8216,9 +8216,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 9, num_already_artifact: 9, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 8e0cc787-e068-4a45-97ed-21029cbe4ddf based on parent blueprint 6d830d26-547e-492b-adfe-c5c4ad9c3751 blueprint source: planner with report: @@ -8342,9 +8342,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 9, num_already_artifact: 9, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint e31c9054-8549-4c68-acf9-a01f68d1fc9b based on parent blueprint 8e0cc787-e068-4a45-97ed-21029cbe4ddf blueprint source: planner with report: @@ -8486,9 +8486,9 @@ INFO performed noop zone image source checks on sled, sled_id: 98e6b7c2-2efa-41c INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: 98e6b7c2-2efa-41ca-b20a-0a4d61102fe6, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a INFO performed noop zone image source checks on sled, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, num_total: 8, num_already_artifact: 8, num_eligible: 0, num_ineligible: 0 INFO BootPartitionDetails inventory hash not found in TUF repo, ignoring for noop checks, sled_id: d81c6a84-79b8-4958-ae41-ea46c9b19763, slot: a, expected_hash: 0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a -INFO skipping board for MGS-driven update, serial_number: serial0, part_number: model0 -INFO skipping board for MGS-driven update, serial_number: serial1, part_number: model1 -INFO skipping board for MGS-driven update, serial_number: serial2, part_number: model2 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial0, part_number: model0 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial1, part_number: model1 +INFO skipping board for MGS-driven update (no update necessary), serial_number: serial2, part_number: model2 INFO ran out of boards for MGS-driven update generated blueprint 3e332949-6785-4aff-ad86-6134f5ce6152 based on parent blueprint e31c9054-8549-4c68-acf9-a01f68d1fc9b blueprint source: planner with report: diff --git a/nexus/reconfigurator/planning/Cargo.toml b/nexus/reconfigurator/planning/Cargo.toml index 0fd3625db71..ed54003c58f 100644 --- a/nexus/reconfigurator/planning/Cargo.toml +++ b/nexus/reconfigurator/planning/Cargo.toml @@ -57,6 +57,7 @@ omicron-workspace-hack.workspace = true [dev-dependencies] dropshot.workspace = true expectorate.workspace = true +hex-literal.workspace = true maplit.workspace = true omicron-common = { workspace = true, features = ["testing"] } omicron-test-utils.workspace = true diff --git a/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs b/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs index 0e7467b04dc..330ee478e6a 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/host_phase_1.rs @@ -12,6 +12,7 @@ use nexus_types::deployment::BlueprintHostPhase2DesiredContents; use nexus_types::deployment::PendingMgsUpdate; use nexus_types::deployment::PendingMgsUpdateDetails; use nexus_types::deployment::PendingMgsUpdateHostPhase1Details; +use nexus_types::deployment::planning_report::FailedMgsUpdateReason; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::Collection; use omicron_common::api::external::TufArtifactMeta; @@ -32,7 +33,7 @@ use tufaceous_artifact::ArtifactKind; /// /// This is generated by the planning process whenever it also generates host /// phase 1 updates. -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq)] pub(crate) struct PendingHostPhase2Changes { by_sled: BTreeMap, } @@ -71,6 +72,10 @@ impl PendingHostPhase2Changes { ); } + pub(super) fn is_empty(&self) -> bool { + self.by_sled.is_empty() + } + pub(crate) fn into_iter( self, ) -> impl Iterator @@ -99,11 +104,6 @@ impl PendingHostPhase2Changes { self.by_sled.remove(sled_id) } - #[cfg(test)] - pub(super) fn is_empty(&self) -> bool { - self.by_sled.is_empty() - } - #[cfg(test)] fn len(&self) -> usize { self.by_sled.len() @@ -265,95 +265,67 @@ pub(super) fn update_status( } } +/// Determine if the given baseboard needs a Host OS update and, if so, +/// returns it. An error means an update is still necessary but cannot be +/// completed. pub(super) fn try_make_update( log: &slog::Logger, baseboard_id: &Arc, inventory: &Collection, current_artifacts: &TufRepoDescription, -) -> Option<(PendingMgsUpdate, PendingHostPhase2Changes)> { + // TODO-K: Instead of this convoluted return type use an enum as suggested in + // https://github.com/oxidecomputer/omicron/pull/9001#discussion_r2372837627 +) -> Result< + Option<(PendingMgsUpdate, PendingHostPhase2Changes)>, + FailedMgsUpdateReason, +> { let Some(sp_info) = inventory.sps.get(baseboard_id) else { - warn!( - log, - "cannot configure host OS update for board \ - (missing SP info from inventory)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::SpNotInInventory); }; // Only configure host OS updates for sleds. // // We don't bother logging a return value of `None` for non-sleds, because // we will never attempt to configure an update for them (nor should we). + // For the same reason, we do not return an error. match sp_info.sp_type { SpType::Sled => (), - SpType::Power | SpType::Switch => return None, + SpType::Power | SpType::Switch => return Ok(None), } let Some(sled_agent) = inventory.sled_agents.iter().find(|sled_agent| { sled_agent.baseboard_id.as_ref() == Some(baseboard_id) }) else { - warn!( - log, - "cannot configure host OS update for board \ - (missing sled-agent info from inventory)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::SledAgentInfoNotInInventory); }; let Some(last_reconciliation) = sled_agent.last_reconciliation.as_ref() else { - warn!( - log, - "cannot configure host OS update for board \ - (missing last reconciliation details from inventory)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::LastReconciliationNotInInventory); }; let boot_disk = match &last_reconciliation.boot_partitions.boot_disk { Ok(boot_disk) => *boot_disk, Err(err) => { - // This error is a `String`; we can't use `InlineErrorChain`. - let err: &str = &err; - warn!( - log, - "cannot configure host OS update for board \ - (sled-agent reported an error determining boot disk)"; - baseboard_id, - "err" => err, - ); - return None; + return Err(FailedMgsUpdateReason::UnableToDetermineBootDisk( + err.to_string(), + )); } }; let active_phase_2_hash = match &last_reconciliation.boot_partitions.slot_details(boot_disk) { Ok(details) => details.artifact_hash, Err(err) => { - // This error is a `String`; we can't use `InlineErrorChain`. - let err: &str = &err; - warn!( - log, - "cannot configure host OS update for board \ - (sled-agent reported an error boot disk phase 2 image)"; - baseboard_id, - "boot_disk" => ?boot_disk, - "err" => err, + return Err( + FailedMgsUpdateReason::UnableToRetrieveBootDiskPhase2Image( + err.to_string(), + ), ); - return None; } }; let Some(active_phase_1_slot) = inventory.host_phase_1_active_slot_for(baseboard_id).map(|s| s.slot) else { - warn!( - log, - "cannot configure host OS update for board \ - (inventory missing current active host phase 1 slot)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::ActiveHostPhase1SlotNotInInventory); }; // TODO-correctness What should we do if the active phase 1 slot doesn't @@ -368,29 +340,20 @@ pub(super) fn try_make_update( // 1 slot and the boot disk, they'll induce a support case to recover, given // this current implementation. As far as we know they shouldn't happen. if active_phase_1_slot != boot_disk { - warn!( - log, - "cannot configure host OS update for board (active phase 1 slot \ - doesn't match boot disk; is the sled already being updated?)"; - baseboard_id, - "active_phase_1_slot" => ?active_phase_1_slot, - "boot_disk" => ?boot_disk, + return Err( + FailedMgsUpdateReason::ActiveHostPhase1SlotBootDiskMismatch( + active_phase_1_slot, + ), ); - return None; } let Some(active_phase_1_hash) = inventory .host_phase_1_flash_hash_for(active_phase_1_slot, baseboard_id) .map(|h| h.hash) else { - warn!( - log, - "cannot configure host OS update for board \ - (missing active phase 1 hash from inventory)"; - baseboard_id, - "slot" => ?active_phase_1_slot, - ); - return None; + return Err(FailedMgsUpdateReason::ActiveHostPhase1HashNotInInventory( + active_phase_1_slot, + )); }; let Some(inactive_phase_1_hash) = inventory @@ -407,7 +370,11 @@ pub(super) fn try_make_update( baseboard_id, "slot" => ?active_phase_1_slot.toggled(), ); - return None; + return Err( + FailedMgsUpdateReason::InactiveHostPhase1HashNotInInventory( + active_phase_1_slot.toggled(), + ), + ); }; let mut phase_1_artifacts = Vec::with_capacity(1); @@ -427,37 +394,17 @@ pub(super) fn try_make_update( ([p1], [p2]) => (p1, p2), // "TUF is broken" cases: missing one or the other. ([], _) => { - warn!( - log, - "cannot configure host OS update for board \ - (no phase 1 artifact)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::NoMatchingArtifactFound); } (_, []) => { - warn!( - log, - "cannot configure host OS update for board \ - (no phase 2 artifact)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::NoMatchingArtifactFound); } // "TUF is broken" cases: have multiple of one or the other. This // should be impossible unless we shipped a TUF repo with multiple // host OS images. We can't proceed, because we don't know how to // pair up which phase 1 matches which phase 2. (_, _) => { - warn!( - log, - "cannot configure host OS update for board \ - (multiple OS images in TUF repo)"; - baseboard_id, - "num-phase-1-images" => phase_1_artifacts.len(), - "num-phase-2-images" => phase_2_artifacts.len(), - ); - return None; + return Err(FailedMgsUpdateReason::TooManyMatchingArtifacts); } }; @@ -469,7 +416,7 @@ pub(super) fn try_make_update( // this sled will fail to boot if it were rebooted now.) if active_phase_2_hash == phase_2_artifact.hash { debug!(log, "no host OS update needed for board"; baseboard_id); - return None; + return Ok(None); } // Before we can proceed with the phase 1 update, we need sled-agent to @@ -485,7 +432,7 @@ pub(super) fn try_make_update( phase_2_artifact, ); - Some(( + Ok(Some(( PendingMgsUpdate { baseboard_id: baseboard_id.clone(), sp_type: sp_info.sp_type, @@ -505,7 +452,7 @@ pub(super) fn try_make_update( artifact_version: phase_1_artifact.id.version.clone(), }, pending_host_phase_2_changes, - )) + ))) } #[cfg(test)] diff --git a/nexus/reconfigurator/planning/src/mgs_updates/mod.rs b/nexus/reconfigurator/planning/src/mgs_updates/mod.rs index 7b85b2c2ef3..fe60c43a074 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/mod.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/mod.rs @@ -20,6 +20,7 @@ use crate::mgs_updates::sp::try_make_update_sp; use gateway_types::rot::RotSlot; use nexus_types::deployment::ExpectedActiveRotSlot; use nexus_types::deployment::ExpectedVersion; +use nexus_types::deployment::MgsUpdateComponent; use nexus_types::deployment::PendingMgsUpdate; use nexus_types::deployment::PendingMgsUpdateDetails; use nexus_types::deployment::PendingMgsUpdateRotBootloaderDetails; @@ -27,6 +28,7 @@ use nexus_types::deployment::PendingMgsUpdateRotDetails; use nexus_types::deployment::PendingMgsUpdateSpDetails; use nexus_types::deployment::PendingMgsUpdates; use nexus_types::deployment::TargetReleaseDescription; +use nexus_types::deployment::planning_report::BlockedMgsUpdate; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::CabooseWhich; use nexus_types::inventory::Collection; @@ -64,6 +66,44 @@ pub(crate) struct PlannedMgsUpdates { /// Pending changes to sleds' host phase 2 contents; each of these should /// result in a change to the respective sled's `BlueprintSledConfig`. pub(crate) pending_host_phase_2_changes: PendingHostPhase2Changes, + + /// Updates to components that cannot be planned due to a failure in a + /// previous attempt. + pub(crate) blocked_mgs_updates: Vec, +} + +impl PlannedMgsUpdates { + fn new() -> Self { + Self { + pending_updates: PendingMgsUpdates::new(), + pending_host_phase_2_changes: PendingHostPhase2Changes::empty(), + blocked_mgs_updates: Vec::new(), + } + } + + fn add_pending_update( + &mut self, + pending_update: PendingMgsUpdate, + ) -> &mut Self { + self.pending_updates.insert(pending_update); + self + } + + fn add_blocked_update( + &mut self, + blocked_update: BlockedMgsUpdate, + ) -> &mut Self { + self.blocked_mgs_updates.push(blocked_update); + self + } + + fn set_pending_host_os_phase2_changes( + &mut self, + pending_host_os_phase2_changes: PendingHostPhase2Changes, + ) -> &mut Self { + self.pending_host_phase_2_changes = pending_host_os_phase2_changes; + self + } } /// Generates a new set of `PendingMgsUpdates` based on: @@ -93,6 +133,7 @@ pub(crate) fn plan_mgs_updates( let mut pending_updates = PendingMgsUpdates::new(); let mut pending_host_phase_2_changes = PendingHostPhase2Changes::empty(); let mut boards_preferred = BTreeSet::new(); + let mut blocked_mgs_updates = Vec::new(); // Determine the status of all currently pending updates by comparing what // they were trying to do (and their preconditions) against the current @@ -162,13 +203,15 @@ pub(crate) fn plan_mgs_updates( // containing artifacts), then we cannot configure more updates. let current_artifacts = match current_artifacts { TargetReleaseDescription::Initial => { - warn!( + info!( log, - "cannot issue more MGS-driven updates (no current artifacts)", + "system in initial release state \ + no update artifacts available (no update necessary)", ); return PlannedMgsUpdates { pending_updates, pending_host_phase_2_changes, + blocked_mgs_updates, }; } TargetReleaseDescription::TufRepo(description) => description, @@ -194,23 +237,40 @@ pub(crate) fn plan_mgs_updates( return PlannedMgsUpdates { pending_updates, pending_host_phase_2_changes, + blocked_mgs_updates, }; } - match try_make_update(log, board, inventory, current_artifacts) { - Some((update, mut host_phase_2)) => { - info!(log, "configuring MGS-driven update"; &update); - pending_updates.insert(update); - pending_host_phase_2_changes.append(&mut host_phase_2); - } - None => { - info!(log, "skipping board for MGS-driven update"; board); + // `try_make_update` will always return at most a single update at a + // time. This means that this instance of `PlannedMgsUpdates` describes + // a single device update + let PlannedMgsUpdates { + pending_updates: updates, + pending_host_phase_2_changes: mut host_phase_2, + blocked_mgs_updates: mut blocked_updates, + } = try_make_update(log, board, inventory, current_artifacts); + + if let Some(update) = updates.into_iter().next() { + info!(log, "configuring MGS-driven update"; update); + pending_updates.insert(update.clone()); + } else { + if blocked_mgs_updates.is_empty() && host_phase_2.is_empty() { + info!(log, "skipping board for MGS-driven update (no update necessary)"; board); + } else { + info!(log, "skipping board for MGS-driven update (found issues)"; board); } } + + pending_host_phase_2_changes.append(&mut host_phase_2); + blocked_mgs_updates.append(&mut blocked_updates); } info!(log, "ran out of boards for MGS-driven update"); - PlannedMgsUpdates { pending_updates, pending_host_phase_2_changes } + PlannedMgsUpdates { + pending_updates, + pending_host_phase_2_changes, + blocked_mgs_updates, + } } #[derive(Debug)] @@ -495,33 +555,91 @@ fn try_make_update( baseboard_id: &Arc, inventory: &Collection, current_artifacts: &TufRepoDescription, -) -> Option<(PendingMgsUpdate, PendingHostPhase2Changes)> { +) -> PlannedMgsUpdates { + let mut pending_actions = PlannedMgsUpdates::new(); + // We try MGS-driven update components in a hardcoded priority order until // any of them returns `Some`. The order is described in RFD 565 section // "Update Sequence". - if let Some(update) = try_make_update_rot_bootloader( - log, - baseboard_id, - inventory, - current_artifacts, - ) - .or_else(|| { - try_make_update_rot(log, baseboard_id, inventory, current_artifacts) - }) - .or_else(|| { - try_make_update_sp(log, baseboard_id, inventory, current_artifacts) - }) { - // We have a non-host update; there are no pending host phase 2 changes - // necessary. - return Some((update, PendingHostPhase2Changes::empty())); + for component in [ + MgsUpdateComponent::RotBootloader, + MgsUpdateComponent::Rot, + MgsUpdateComponent::Sp, + MgsUpdateComponent::HostOs, + ] { + let update_attempt = match component { + MgsUpdateComponent::RotBootloader => { + try_make_update_rot_bootloader( + log, + baseboard_id, + inventory, + current_artifacts, + ) + } + MgsUpdateComponent::Rot => try_make_update_rot( + log, + baseboard_id, + inventory, + current_artifacts, + ), + MgsUpdateComponent::Sp => try_make_update_sp( + log, + baseboard_id, + inventory, + current_artifacts, + ), + MgsUpdateComponent::HostOs => { + match host_phase_1::try_make_update( + log, + baseboard_id, + inventory, + current_artifacts, + ) { + Ok(pending_update) => { + // Host updates also return host OS phase 2 changes; + // pull those out here and insert them into + // `pending_actions`, then return the typical pending + // update (which will itself be inserted into + // `pending_actions` below). + if let Some((update, host_os_phase_2_changes)) = + pending_update + { + pending_actions.set_pending_host_os_phase2_changes( + host_os_phase_2_changes, + ); + Ok(Some(update)) + } else { + Ok(None) + } + } + Err(e) => Err(e), + } + } + }; + + match update_attempt { + Ok(None) => { + // No update needed; try the next component. + continue; + } + // If there is a pending or blocked MGS-driven update, we break so + // we can return it immediately. + Ok(Some(update)) => { + pending_actions.add_pending_update(update); + break; + } + Err(e) => { + pending_actions.add_blocked_update(BlockedMgsUpdate { + baseboard_id: baseboard_id.clone(), + component, + reason: e, + }); + break; + } + } } - host_phase_1::try_make_update( - log, - baseboard_id, - inventory, - current_artifacts, - ) + pending_actions } #[cfg(test)] @@ -544,14 +662,218 @@ mod test { use dropshot::ConfigLogging; use dropshot::ConfigLoggingLevel; use gateway_client::types::SpType; + use iddqd::IdOrdMap; use nexus_types::deployment::ExpectedVersion; + use nexus_types::deployment::MgsUpdateComponent; use nexus_types::deployment::PendingMgsUpdateDetails; use nexus_types::deployment::PendingMgsUpdateSpDetails; use nexus_types::deployment::PendingMgsUpdates; use nexus_types::deployment::TargetReleaseDescription; + use nexus_types::deployment::planning_report::BlockedMgsUpdate; + use nexus_types::deployment::planning_report::FailedMgsUpdateReason; + use nexus_types::inventory::BaseboardId; + use nexus_types::inventory::CabooseWhich; use omicron_test_utils::dev::LogContext; + use std::collections::BTreeSet; + use std::sync::Arc; use strum::IntoEnumIterator; + // Confirm our behaviour for skipped updates + #[test] + fn test_blocked_updates() { + let test_name = "planning_mgs_updates_blocked_updates"; + let logctx = LogContext::new( + test_name, + &ConfigLogging::StderrTerminal { level: ConfigLoggingLevel::Debug }, + ); + let log = &logctx.log; + let test_boards = TestBoards::new(test_name); + + // Initial setup: One of every possible SP component will need to be + // updated + let collection = test_boards + .collection_builder() + .stage0_version_exception(SpType::Sled, 0, ARTIFACT_VERSION_1) + .rot_active_version_exception(SpType::Sled, 0, ARTIFACT_VERSION_1) + .sp_active_version_exception(SpType::Sled, 0, ARTIFACT_VERSION_1) + .host_active_exception( + 0, + ARTIFACT_HASH_HOST_PHASE_1_V1, + ARTIFACT_HASH_HOST_PHASE_2_V1, + ) + .build(); + let current_updates = PendingMgsUpdates::new(); + let nmax_updates = 1; + let impossible_update_policy = ImpossibleUpdatePolicy::Reevaluate; + let repo = test_boards.tuf_repo(); + + // Instead of using the baseboards from the collection, we create a new + // fake baseboard that the planner will not recognise + let mut fake_boards = BTreeSet::new(); + let fake_board = Arc::new(BaseboardId { + part_number: "fake_part".to_string(), + serial_number: "fake_serial".to_string(), + }); + fake_boards.insert(fake_board.clone()); + + let PlannedMgsUpdates { + pending_updates: updates, + blocked_mgs_updates, + .. + } = plan_mgs_updates( + log, + &collection, + &fake_boards, + ¤t_updates, + &TargetReleaseDescription::TufRepo(repo.clone()), + nmax_updates, + impossible_update_policy, + ); + + // The planner should only gather the first failed update (RoT + // bootloader), and report no pending updates. There will only be a + // single entry as there is only a single fake board. + let expected_blocked_updates = vec![BlockedMgsUpdate { + baseboard_id: fake_board.clone(), + component: MgsUpdateComponent::RotBootloader, + reason: FailedMgsUpdateReason::SpNotInInventory, + }]; + assert_eq!(blocked_mgs_updates, expected_blocked_updates); + assert!(updates.is_empty()); + + // Now we build a the collection so it only reports updates necessary + // for the RoT, SP and Host OS. + let mut collection = test_boards + .collection_builder() + .rot_active_version_exception(SpType::Sled, 0, ARTIFACT_VERSION_1) + .sp_active_version_exception(SpType::Sled, 0, ARTIFACT_VERSION_1) + .host_active_exception( + 0, + ARTIFACT_HASH_HOST_PHASE_1_V1, + ARTIFACT_HASH_HOST_PHASE_2_V1, + ) + .build(); + + // Let's remove all RoT information to force a failed update + for baseboard_id in &collection.baseboards { + collection.rots.remove(baseboard_id); + } + + let PlannedMgsUpdates { + pending_updates: updates, + blocked_mgs_updates, + .. + } = plan_mgs_updates( + log, + &collection, + &collection.baseboards, + ¤t_updates, + &TargetReleaseDescription::TufRepo(repo.clone()), + nmax_updates, + impossible_update_policy, + ); + + // The planner should only gather the first RoT failed update of + // each of the boards, and report no pending updates + let mut expected_blocked_updates = Vec::new(); + for baseboard_id in &collection.baseboards { + expected_blocked_updates.push(BlockedMgsUpdate { + baseboard_id: baseboard_id.clone(), + component: MgsUpdateComponent::Rot, + reason: FailedMgsUpdateReason::RotStateNotInInventory, + }); + } + assert_eq!(blocked_mgs_updates, expected_blocked_updates); + assert!(updates.is_empty()); + + // Like before we build a collection that only reports updates necessary + // for the SP and Host OS. + let mut collection = test_boards + .collection_builder() + .sp_active_version_exception(SpType::Sled, 0, ARTIFACT_VERSION_1) + .host_active_exception( + 0, + ARTIFACT_HASH_HOST_PHASE_1_V1, + ARTIFACT_HASH_HOST_PHASE_2_V1, + ) + .build(); + + // Let's remove SP slot 0 caboose information to force a failed update + collection.cabooses_found.remove(&CabooseWhich::SpSlot0); + + let PlannedMgsUpdates { + pending_updates: updates, + blocked_mgs_updates, + .. + } = plan_mgs_updates( + log, + &collection, + &collection.baseboards, + ¤t_updates, + &TargetReleaseDescription::TufRepo(repo.clone()), + nmax_updates, + impossible_update_policy, + ); + + // The planner should only gather the first SP failed update of + // each of the boards, and report no pending updates + let mut expected_blocked_updates = Vec::new(); + for baseboard_id in &collection.baseboards { + expected_blocked_updates.push(BlockedMgsUpdate { + baseboard_id: baseboard_id.clone(), + component: MgsUpdateComponent::Sp, + reason: FailedMgsUpdateReason::CabooseNotInInventory( + CabooseWhich::SpSlot0, + ), + }); + } + assert_eq!(blocked_mgs_updates, expected_blocked_updates); + assert!(updates.is_empty()); + + // Now we create one more collection where only the Host OS needs an + // update + let mut collection = test_boards + .collection_builder() + .host_active_exception( + 0, + ARTIFACT_HASH_HOST_PHASE_1_V1, + ARTIFACT_HASH_HOST_PHASE_2_V1, + ) + .build(); + + // Remove sled agent info to force a failed update + collection.sled_agents = IdOrdMap::new(); + + let PlannedMgsUpdates { + pending_updates: updates, + blocked_mgs_updates, + .. + } = plan_mgs_updates( + log, + &collection, + &collection.baseboards, + ¤t_updates, + &TargetReleaseDescription::TufRepo(repo.clone()), + nmax_updates, + impossible_update_policy, + ); + + // The planner should only gather the first Host OS failed update of + // each of the sled boards, and report no pending updates + let mut expected_blocked_updates = Vec::new(); + for baseboard_id in &collection.baseboards { + if baseboard_id.part_number == "dummy_sled" { + expected_blocked_updates.push(BlockedMgsUpdate { + baseboard_id: baseboard_id.clone(), + component: MgsUpdateComponent::HostOs, + reason: FailedMgsUpdateReason::SledAgentInfoNotInInventory, + }); + } + } + assert_eq!(blocked_mgs_updates, expected_blocked_updates); + assert!(updates.is_empty()); + } + // Confirm our behavior for impossible updates #[test] fn test_impossible_update_policy() { @@ -738,6 +1060,7 @@ mod test { let PlannedMgsUpdates { pending_updates: new_updates, mut pending_host_phase_2_changes, + .. } = plan_mgs_updates( log, &collection, @@ -866,6 +1189,7 @@ mod test { let PlannedMgsUpdates { pending_updates: all_updates, mut pending_host_phase_2_changes, + .. } = plan_mgs_updates( log, &collection, @@ -910,6 +1234,7 @@ mod test { let PlannedMgsUpdates { pending_updates: all_updates, mut pending_host_phase_2_changes, + .. } = plan_mgs_updates( log, &collection, @@ -952,6 +1277,7 @@ mod test { let PlannedMgsUpdates { pending_updates: all_updates, mut pending_host_phase_2_changes, + .. } = plan_mgs_updates( log, &collection, @@ -993,6 +1319,7 @@ mod test { let PlannedMgsUpdates { pending_updates: all_updates, mut pending_host_phase_2_changes, + .. } = plan_mgs_updates( log, &collection, @@ -1026,6 +1353,7 @@ mod test { let PlannedMgsUpdates { pending_updates: all_updates_done, pending_host_phase_2_changes, + .. } = plan_mgs_updates( log, &collection, diff --git a/nexus/reconfigurator/planning/src/mgs_updates/rot.rs b/nexus/reconfigurator/planning/src/mgs_updates/rot.rs index 2c3b47bc6f1..450a312059b 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/rot.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/rot.rs @@ -13,6 +13,7 @@ use nexus_types::deployment::ExpectedVersion; use nexus_types::deployment::PendingMgsUpdate; use nexus_types::deployment::PendingMgsUpdateDetails; use nexus_types::deployment::PendingMgsUpdateRotDetails; +use nexus_types::deployment::planning_report::FailedMgsUpdateReason; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::CabooseWhich; use nexus_types::inventory::Collection; @@ -100,67 +101,49 @@ pub fn mgs_update_status_rot( } /// Determine if the given baseboard needs an RoT update and, if so, returns it. +/// An error means an update is still necessary but cannot be completed. pub fn try_make_update_rot( log: &slog::Logger, baseboard_id: &Arc, inventory: &Collection, current_artifacts: &TufRepoDescription, -) -> Option { + // TODO-K: Like the Host OS, use an enum here as the return type as suggested in + // https://github.com/oxidecomputer/omicron/pull/9001#discussion_r2372837627 +) -> Result, FailedMgsUpdateReason> { let Some(sp_info) = inventory.sps.get(baseboard_id) else { - warn!( - log, - "cannot configure RoT update for board \ - (missing SP info from inventory)"; - baseboard_id - ); - return None; + return Err(FailedMgsUpdateReason::SpNotInInventory); }; let Some(rot_state) = inventory.rots.get(baseboard_id) else { - warn!( - log, - "cannot configure RoT update for board \ - (missing RoT state from inventory)"; - baseboard_id - ); - return None; + return Err(FailedMgsUpdateReason::RotStateNotInInventory); }; let active_slot = rot_state.active_slot; - let Some(active_caboose) = inventory - .caboose_for(CabooseWhich::from_rot_slot(active_slot), baseboard_id) + let active_caboose_which = CabooseWhich::from_rot_slot(active_slot); + let Some(active_caboose) = + inventory.caboose_for(active_caboose_which, baseboard_id) else { - warn!( - log, - "cannot configure RoT update for board \ - (missing active slot {active_slot} caboose from inventory)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::CabooseNotInInventory( + active_caboose_which, + )); }; - let Ok(expected_active_version) = active_caboose.caboose.version.parse() - else { - warn!( - log, - "cannot configure RoT update for board \ - (cannot parse current active version as an ArtifactVersion)"; - baseboard_id, - "found_version" => &active_caboose.caboose.version, - ); - return None; + let expected_active_version = match active_caboose.caboose.version.parse() { + Ok(v) => v, + Err(e) => { + return Err(FailedMgsUpdateReason::FailedVersionParse { + caboose: active_caboose_which, + err: format!("{}", e), + }); + } }; let board = &active_caboose.caboose.board; let Some(rkth) = &active_caboose.caboose.sign else { - warn!( - log, - "cannot configure RoT update for board \ - (missing sign in caboose from inventory)"; - baseboard_id - ); - return None; + return Err(FailedMgsUpdateReason::CabooseMissingSign( + active_caboose_which, + )); }; let matching_artifacts: Vec<_> = current_artifacts @@ -219,12 +202,7 @@ pub fn try_make_update_rot( }) .collect(); if matching_artifacts.is_empty() { - warn!( - log, - "cannot configure RoT update for board (no matching artifact)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::NoMatchingArtifactFound); } if matching_artifacts.len() > 1 { @@ -241,7 +219,7 @@ pub fn try_make_update_rot( // needed. if artifact.id.version == expected_active_version { debug!(log, "no RoT update needed for board"; baseboard_id); - return None; + return Ok(None); } let expected_active_slot = ExpectedActiveRotSlot { @@ -250,28 +228,24 @@ pub fn try_make_update_rot( }; // Begin configuring an update. + let inactive_caboose_which = + CabooseWhich::from_rot_slot(active_slot.toggled()); let expected_inactive_version = match inventory - .caboose_for( - CabooseWhich::from_rot_slot(active_slot.toggled()), - baseboard_id, - ) + .caboose_for(inactive_caboose_which, baseboard_id) .map(|c| c.caboose.version.parse::()) .transpose() { Ok(None) => ExpectedVersion::NoValidVersion, Ok(Some(v)) => ExpectedVersion::Version(v), - Err(_) => { - warn!( - log, - "cannot configure RoT update for board \ - (found inactive slot contents but version was not valid)"; - baseboard_id - ); - return None; + Err(e) => { + return Err(FailedMgsUpdateReason::FailedVersionParse { + caboose: inactive_caboose_which, + err: format!("{}", e), + }); } }; - Some(PendingMgsUpdate { + Ok(Some(PendingMgsUpdate { baseboard_id: baseboard_id.clone(), sp_type: sp_info.sp_type, slot_id: sp_info.sp_slot, @@ -287,7 +261,7 @@ pub fn try_make_update_rot( }), artifact_hash: artifact.hash, artifact_version: artifact.id.version.clone(), - }) + })) } #[cfg(test)] diff --git a/nexus/reconfigurator/planning/src/mgs_updates/rot_bootloader.rs b/nexus/reconfigurator/planning/src/mgs_updates/rot_bootloader.rs index 306099e1d2f..db332d93cc3 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/rot_bootloader.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/rot_bootloader.rs @@ -11,6 +11,7 @@ use nexus_types::deployment::ExpectedVersion; use nexus_types::deployment::PendingMgsUpdate; use nexus_types::deployment::PendingMgsUpdateDetails; use nexus_types::deployment::PendingMgsUpdateRotBootloaderDetails; +use nexus_types::deployment::planning_report::FailedMgsUpdateReason; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::CabooseWhich; use nexus_types::inventory::Collection; @@ -54,56 +55,43 @@ pub fn mgs_update_status_rot_bootloader( } /// Determine if the given baseboard needs an RoT bootloader update and, if so, -/// returns it. +/// returns it. An error means an update is still necessary but cannot be +/// completed. pub fn try_make_update_rot_bootloader( log: &slog::Logger, baseboard_id: &Arc, inventory: &Collection, current_artifacts: &TufRepoDescription, -) -> Option { + // TODO-K: Like the Host OS, use an enum here as the return type as suggested in + // https://github.com/oxidecomputer/omicron/pull/9001#discussion_r2372837627 +) -> Result, FailedMgsUpdateReason> { let Some(sp_info) = inventory.sps.get(baseboard_id) else { - warn!( - log, - "cannot configure RoT bootloader update for board \ - (missing SP info from inventory)"; - baseboard_id - ); - return None; + return Err(FailedMgsUpdateReason::SpNotInInventory); }; let Some(stage0_caboose) = inventory.caboose_for(CabooseWhich::Stage0, baseboard_id) else { - warn!( - log, - "cannot configure RoT bootloader update for board \ - (missing stage0 caboose from inventory)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::CabooseNotInInventory( + CabooseWhich::Stage0, + )); }; - let Ok(expected_stage0_version) = stage0_caboose.caboose.version.parse() - else { - warn!( - log, - "cannot configure RoT bootloader update for board \ - (cannot parse current stage0 version as an ArtifactVersion)"; - baseboard_id, - "found_version" => &stage0_caboose.caboose.version, - ); - return None; + let expected_stage0_version = match stage0_caboose.caboose.version.parse() { + Ok(v) => v, + Err(e) => { + return Err(FailedMgsUpdateReason::FailedVersionParse { + caboose: CabooseWhich::Stage0, + err: format!("{}", e), + }); + } }; let board = &stage0_caboose.caboose.board; let Some(rkth) = &stage0_caboose.caboose.sign else { - warn!( - log, - "cannot configure RoT bootloader update for board \ - (missing sign in stage0 caboose from inventory)"; - baseboard_id - ); - return None; + return Err(FailedMgsUpdateReason::CabooseMissingSign( + CabooseWhich::Stage0, + )); }; let matching_artifacts: Vec<_> = current_artifacts @@ -155,12 +143,7 @@ pub fn try_make_update_rot_bootloader( }) .collect(); if matching_artifacts.is_empty() { - warn!( - log, - "cannot configure RoT bootloader update for board (no matching artifact)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::NoMatchingArtifactFound); } if matching_artifacts.len() > 1 { @@ -180,7 +163,7 @@ pub fn try_make_update_rot_bootloader( // needed. if artifact.id.version == expected_stage0_version { debug!(log, "no RoT bootloader update needed for board"; baseboard_id); - return None; + return Ok(None); } // Begin configuring an update. @@ -191,18 +174,15 @@ pub fn try_make_update_rot_bootloader( { Ok(None) => ExpectedVersion::NoValidVersion, Ok(Some(v)) => ExpectedVersion::Version(v), - Err(_) => { - warn!( - log, - "cannot configure RoT bootloader update for board \ - (found stage0 next contents but version was not valid)"; - baseboard_id - ); - return None; + Err(e) => { + return Err(FailedMgsUpdateReason::FailedVersionParse { + caboose: CabooseWhich::Stage0Next, + err: format!("{}", e), + }); } }; - Some(PendingMgsUpdate { + Ok(Some(PendingMgsUpdate { baseboard_id: baseboard_id.clone(), sp_type: sp_info.sp_type, slot_id: sp_info.sp_slot, @@ -214,7 +194,7 @@ pub fn try_make_update_rot_bootloader( ), artifact_hash: artifact.hash, artifact_version: artifact.id.version.clone(), - }) + })) } #[cfg(test)] diff --git a/nexus/reconfigurator/planning/src/mgs_updates/sp.rs b/nexus/reconfigurator/planning/src/mgs_updates/sp.rs index 638bb612f23..4694186f096 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/sp.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/sp.rs @@ -11,6 +11,7 @@ use nexus_types::deployment::ExpectedVersion; use nexus_types::deployment::PendingMgsUpdate; use nexus_types::deployment::PendingMgsUpdateDetails; use nexus_types::deployment::PendingMgsUpdateSpDetails; +use nexus_types::deployment::planning_report::FailedMgsUpdateReason; use nexus_types::inventory::BaseboardId; use nexus_types::inventory::CabooseWhich; use nexus_types::inventory::Collection; @@ -54,44 +55,35 @@ pub fn mgs_update_status_sp( } /// Determine if the given baseboard needs an SP update and, if so, returns it. +/// An error means an update is still necessary but cannot be completed. pub fn try_make_update_sp( log: &slog::Logger, baseboard_id: &Arc, inventory: &Collection, current_artifacts: &TufRepoDescription, -) -> Option { + // TODO-K: Like the Host OS, use an enum here as the return type as suggested in + // https://github.com/oxidecomputer/omicron/pull/9001#discussion_r2372837627 +) -> Result, FailedMgsUpdateReason> { 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; + return Err(FailedMgsUpdateReason::SpNotInInventory); }; 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; + return Err(FailedMgsUpdateReason::CabooseNotInInventory( + CabooseWhich::SpSlot0, + )); }; - 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 expected_active_version = match active_caboose.caboose.version.parse() { + Ok(v) => v, + Err(e) => { + return Err(FailedMgsUpdateReason::FailedVersionParse { + caboose: CabooseWhich::SpSlot0, + err: format!("{}", e), + }); + } }; let board = &active_caboose.caboose.board; @@ -132,12 +124,7 @@ pub fn try_make_update_sp( }) .collect(); if matching_artifacts.is_empty() { - warn!( - log, - "cannot configure SP update for board (no matching artifact)"; - baseboard_id, - ); - return None; + return Err(FailedMgsUpdateReason::NoMatchingArtifactFound); } if matching_artifacts.len() > 1 { @@ -153,7 +140,7 @@ pub fn try_make_update_sp( // needed. if artifact.id.version == expected_active_version { debug!(log, "no SP update needed for board"; baseboard_id); - return None; + return Ok(None); } // Begin configuring an update. @@ -164,18 +151,15 @@ pub fn try_make_update_sp( { 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; + Err(e) => { + return Err(FailedMgsUpdateReason::FailedVersionParse { + caboose: CabooseWhich::SpSlot1, + err: format!("{}", e), + }); } }; - Some(PendingMgsUpdate { + Ok(Some(PendingMgsUpdate { baseboard_id: baseboard_id.clone(), sp_type: sp_info.sp_type, slot_id: sp_info.sp_slot, @@ -185,7 +169,7 @@ pub fn try_make_update_sp( }), artifact_hash: artifact.hash, artifact_version: artifact.id.version.clone(), - }) + })) } #[cfg(test)] diff --git a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs index 2e6f951e6cb..6d2e679d1e6 100644 --- a/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs +++ b/nexus/reconfigurator/planning/src/mgs_updates/test_helpers.rs @@ -32,6 +32,7 @@ use nexus_sled_agent_shared::inventory::ZoneImageResolverInventory; use nexus_types::deployment::BlueprintArtifactVersion; use nexus_types::deployment::BlueprintHostPhase2DesiredContents; use nexus_types::deployment::ExpectedVersion; +use nexus_types::deployment::MgsUpdateComponent; use nexus_types::deployment::PendingMgsUpdate; use nexus_types::deployment::PendingMgsUpdateDetails; use nexus_types::deployment::PendingMgsUpdateHostPhase1Details; @@ -140,27 +141,6 @@ const ROT_SIGN_PSC: &str = const ROT_SIGN_SWITCH: &str = "3333333333333333333333333333333333333333333333333333333333333333"; -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] -pub(super) enum MgsUpdateComponent { - Sp, - Rot, - RotBootloader, - HostOs, -} - -impl From<&'_ PendingMgsUpdateDetails> for MgsUpdateComponent { - fn from(value: &'_ PendingMgsUpdateDetails) -> Self { - match value { - PendingMgsUpdateDetails::Rot { .. } => Self::Rot, - PendingMgsUpdateDetails::RotBootloader { .. } => { - Self::RotBootloader - } - PendingMgsUpdateDetails::Sp { .. } => Self::Sp, - PendingMgsUpdateDetails::HostPhase1(_) => Self::HostOs, - } - } -} - /// Description of a single fake board (sled, switch, or PSC). #[derive(Debug)] pub(super) struct TestBoard { @@ -635,7 +615,7 @@ impl ExpectedUpdates { ) { let sp_type = update.sp_type; let sp_slot = update.slot_id; - let component = MgsUpdateComponent::from(&update.details); + let component: MgsUpdateComponent = (&update.details).into(); println!("found update: {} slot {}", sp_type, sp_slot); let ExpectedUpdate { expected_serial, expected_artifact, .. } = self .updates diff --git a/nexus/reconfigurator/planning/src/planner.rs b/nexus/reconfigurator/planning/src/planner.rs index 331835793d6..847c1c1ee01 100644 --- a/nexus/reconfigurator/planning/src/planner.rs +++ b/nexus/reconfigurator/planning/src/planner.rs @@ -38,7 +38,6 @@ use nexus_types::deployment::CockroachDbClusterVersion; use nexus_types::deployment::CockroachDbPreserveDowngrade; use nexus_types::deployment::CockroachDbSettings; use nexus_types::deployment::DiskFilter; -use nexus_types::deployment::PendingMgsUpdates; use nexus_types::deployment::PlanningInput; use nexus_types::deployment::SledDetails; use nexus_types::deployment::SledFilter; @@ -236,7 +235,7 @@ impl<'a> Planner<'a> { let mgs_updates = if add_update_blocked_reasons.is_empty() { self.do_plan_mgs_updates()? } else { - PlanningMgsUpdatesStepReport::new(PendingMgsUpdates::new()) + PlanningMgsUpdatesStepReport::empty() }; // Likewise for zone additions, unless overridden by the config, or @@ -272,13 +271,18 @@ impl<'a> Planner<'a> { PlanningZoneUpdatesStepReport::waiting_on( ZoneUpdatesWaitingOn::DiscretionaryZones, ) - } else if !mgs_updates.is_empty() { + } else if !mgs_updates.pending_mgs_updates.is_empty() { // ... or if there are still pending updates for the RoT / SP / // Host OS / etc. ... - // TODO This is not quite right. See oxidecomputer/omicron#8285. PlanningZoneUpdatesStepReport::waiting_on( ZoneUpdatesWaitingOn::PendingMgsUpdates, ) + } else if !mgs_updates.blocked_mgs_updates.is_empty() { + // ... or if there are blocked updates for the RoT / SP / Host OS / + // RoT bootloader. + PlanningZoneUpdatesStepReport::waiting_on( + ZoneUpdatesWaitingOn::BlockedMgsUpdates, + ) } else if !add.add_update_blocked_reasons.is_empty() { // ... or if there are pending zone add blockers. PlanningZoneUpdatesStepReport::waiting_on( @@ -1430,16 +1434,19 @@ impl<'a> Planner<'a> { } else { ImpossibleUpdatePolicy::Reevaluate }; - let PlannedMgsUpdates { pending_updates, pending_host_phase_2_changes } = - plan_mgs_updates( - &self.log, - &self.inventory, - &included_baseboards, - current_updates, - current_artifacts, - NUM_CONCURRENT_MGS_UPDATES, - impossible_update_policy, - ); + let PlannedMgsUpdates { + pending_updates, + pending_host_phase_2_changes, + blocked_mgs_updates, + } = plan_mgs_updates( + &self.log, + &self.inventory, + &included_baseboards, + current_updates, + current_artifacts, + NUM_CONCURRENT_MGS_UPDATES, + impossible_update_policy, + ); if pending_updates != *current_updates { // This will only add comments if our set of updates changed _and_ // we have at least one update. If we went from "some updates" to @@ -1453,7 +1460,10 @@ impl<'a> Planner<'a> { .apply_pending_host_phase_2_changes(pending_host_phase_2_changes)?; self.blueprint.pending_mgs_updates_replace_all(pending_updates.clone()); - Ok(PlanningMgsUpdatesStepReport::new(pending_updates)) + Ok(PlanningMgsUpdatesStepReport::new( + pending_updates, + blocked_mgs_updates, + )) } // Returns the zones which appear in the blueprint on commissioned sleds, @@ -6240,7 +6250,7 @@ pub(crate) mod test { }; } - fn create_artifacts_at_version( + fn create_zone_artifacts_at_version( version: &ArtifactVersion, ) -> Vec { vec![ @@ -6257,6 +6267,66 @@ pub(crate) mod test { fake_zone_artifact!(InternalNtp, version.clone()), fake_zone_artifact!(Nexus, version.clone()), fake_zone_artifact!(Oximeter, version.clone()), + // We create artifacts with the versions (or hash) set to those of + // the example system to simulate an environment that does not need + // SP component updates. + TufArtifactMeta { + id: ArtifactId { + name: "host-os-phase-1".to_string(), + version: version.clone(), + kind: ArtifactKind::GIMLET_HOST_PHASE_1, + }, + hash: ArtifactHash([1; 32]), + size: 0, + board: None, + sign: None, + }, + TufArtifactMeta { + id: ArtifactId { + name: "host-os-phase-2".to_string(), + version: version.clone(), + kind: ArtifactKind::HOST_PHASE_2, + }, + hash: ArtifactHash(hex_literal::hex!( + "7cd830e1682d50620de0f5c24b8cca15937eb10d2a415ade6ad28c0d314408eb" + )), + size: 0, + board: None, + sign: None, + }, + TufArtifactMeta { + id: ArtifactId { + name: sp_sim::SIM_GIMLET_BOARD.to_string(), + version: ArtifactVersion::new("0.0.1").unwrap(), + kind: KnownArtifactKind::GimletSp.into(), + }, + hash: ArtifactHash([0; 32]), + size: 0, + board: Some(sp_sim::SIM_GIMLET_BOARD.to_string()), + sign: None, + }, + TufArtifactMeta { + id: ArtifactId { + name: sp_sim::SIM_ROT_BOARD.to_string(), + version: ArtifactVersion::new("0.0.1").unwrap(), + kind: ArtifactKind::GIMLET_ROT_IMAGE_B, + }, + hash: ArtifactHash([0; 32]), + size: 0, + board: Some(sp_sim::SIM_ROT_BOARD.to_string()), + sign: Some("sign-gimlet".into()), + }, + TufArtifactMeta { + id: ArtifactId { + name: sp_sim::SIM_ROT_BOARD.to_string(), + version: ArtifactVersion::new("0.0.1").unwrap(), + kind: ArtifactKind::GIMLET_ROT_STAGE0, + }, + hash: ArtifactHash([0; 32]), + size: 0, + board: Some(sp_sim::SIM_ROT_BOARD.to_string()), + sign: Some("sign-gimlet".into()), + }, ] } @@ -6312,7 +6382,7 @@ pub(crate) mod test { }, hash: fake_hash, }; - let artifacts = create_artifacts_at_version(&version); + let artifacts = create_zone_artifacts_at_version(&version); let description = TargetReleaseDescription::TufRepo(TufRepoDescription { repo: TufRepoMeta { @@ -6768,7 +6838,7 @@ pub(crate) mod test { }, hash: fake_hash, }; - let artifacts = create_artifacts_at_version(&version); + let artifacts = create_zone_artifacts_at_version(&version); let description = TargetReleaseDescription::TufRepo(TufRepoDescription { repo: TufRepoMeta { @@ -7199,7 +7269,7 @@ pub(crate) mod test { }, hash: fake_hash, }; - let artifacts = create_artifacts_at_version(&version); + let artifacts = create_zone_artifacts_at_version(&version); let description = TargetReleaseDescription::TufRepo(TufRepoDescription { repo: TufRepoMeta { @@ -7637,8 +7707,7 @@ pub(crate) mod test { }, hash: fake_hash, }; - let artifacts = create_artifacts_at_version(&version); - + let artifacts = create_zone_artifacts_at_version(&version); let description = TargetReleaseDescription::TufRepo(TufRepoDescription { repo: TufRepoMeta { @@ -7910,7 +7979,8 @@ pub(crate) mod test { }, hash: fake_hash, }; - + // We use generation 2 to represent the first generation with a TUF repo + // attached. let description = TargetReleaseDescription::TufRepo(TufRepoDescription { repo: TufRepoMeta { @@ -7920,7 +7990,7 @@ pub(crate) mod test { system_version: Version::new(1, 0, 0), file_name: String::from(""), }, - artifacts: create_artifacts_at_version(&version), + artifacts: create_zone_artifacts_at_version(&version), }); example.system.set_target_release_and_old_repo(description); @@ -8248,12 +8318,12 @@ pub(crate) mod test { // Next: Set the target to "2.0.0", upgrade everything except // Nexus. bp_generator.set_new_tuf_repo_with_artifacts( - create_artifacts_at_version(&artifact_version_1), + create_zone_artifacts_at_version(&artifact_version_1), Version::new(1, 0, 0), ); bp_generator.set_old_tuf_repo_to_target(); bp_generator.set_new_tuf_repo_with_artifacts( - create_artifacts_at_version(&artifact_version_2), + create_zone_artifacts_at_version(&artifact_version_2), Version::new(2, 0, 0), ); let image_source_1 = @@ -8374,6 +8444,8 @@ pub(crate) mod test { rng.next_system_rng(), ) .nexus_count(3) + .with_target_release_0_0_1() + .expect("set target release to 0.0.1") .build(); verify_blueprint(&blueprint); @@ -8396,8 +8468,11 @@ pub(crate) mod test { .blueprint .all_omicron_zones(BlueprintZoneDisposition::is_in_service) .all(|(_, z)| matches!( - z.image_source, - BlueprintZoneImageSource::InstallDataset + &z.image_source, + BlueprintZoneImageSource::Artifact { version, hash: _ } + if version == &BlueprintArtifactVersion::Available { + version: ArtifactVersion::new_const("0.0.1") + } )) ); @@ -8409,12 +8484,12 @@ pub(crate) mod test { ArtifactVersion::new_static("2.0.0-nexus-gen-test") .expect("can't parse artifact version"); bp_generator.set_new_tuf_repo_with_artifacts( - create_artifacts_at_version(&artifact_version_1), + create_zone_artifacts_at_version(&artifact_version_1), Version::new(1, 0, 0), ); bp_generator.set_old_tuf_repo_to_target(); bp_generator.set_new_tuf_repo_with_artifacts( - create_artifacts_at_version(&artifact_version_2), + create_zone_artifacts_at_version(&artifact_version_2), Version::new(2, 0, 0), ); let image_source_1 = diff --git a/nexus/types/src/deployment.rs b/nexus/types/src/deployment.rs index e9f86155834..35006b35dec 100644 --- a/nexus/types/src/deployment.rs +++ b/nexus/types/src/deployment.rs @@ -58,6 +58,7 @@ use slog::Key; use std::collections::BTreeMap; use std::collections::BTreeSet; use std::fmt; +use std::fmt::Display; use std::net::Ipv6Addr; use std::net::SocketAddrV6; use std::sync::Arc; @@ -72,7 +73,7 @@ mod clickhouse; pub mod execution; mod network_resources; mod planning_input; -mod planning_report; +pub mod planning_report; mod reconfigurator_config; mod zone_type; @@ -1451,6 +1452,39 @@ impl fmt::Display for BlueprintHostPhase2DesiredContents { } } +#[derive( + Debug, + Deserialize, + Serialize, + PartialEq, + Eq, + Diffable, + PartialOrd, + JsonSchema, + Ord, + Clone, + Copy, +)] +#[serde(rename_all = "snake_case")] +pub enum MgsUpdateComponent { + Sp, + Rot, + RotBootloader, + HostOs, +} + +impl Display for MgsUpdateComponent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let s = match self { + MgsUpdateComponent::HostOs => "Host OS", + MgsUpdateComponent::Rot => "RoT", + MgsUpdateComponent::RotBootloader => "RoT Bootloader", + MgsUpdateComponent::Sp => "SP", + }; + write!(f, "{s}") + } +} + #[derive( Clone, Debug, Eq, PartialEq, Deserialize, Serialize, JsonSchema, Diffable, )] @@ -1638,6 +1672,21 @@ pub enum PendingMgsUpdateDetails { HostPhase1(PendingMgsUpdateHostPhase1Details), } +impl From<&PendingMgsUpdateDetails> for MgsUpdateComponent { + fn from(details: &PendingMgsUpdateDetails) -> Self { + match &details { + PendingMgsUpdateDetails::Rot { .. } => MgsUpdateComponent::Rot, + PendingMgsUpdateDetails::RotBootloader { .. } => { + MgsUpdateComponent::RotBootloader + } + PendingMgsUpdateDetails::Sp { .. } => MgsUpdateComponent::Sp, + PendingMgsUpdateDetails::HostPhase1(_) => { + MgsUpdateComponent::HostOs + } + } + } +} + impl slog::KV for PendingMgsUpdateDetails { fn serialize( &self, diff --git a/nexus/types/src/deployment/blueprint_diff.rs b/nexus/types/src/deployment/blueprint_diff.rs index 55d36a4a89e..4541c49d765 100644 --- a/nexus/types/src/deployment/blueprint_diff.rs +++ b/nexus/types/src/deployment/blueprint_diff.rs @@ -2140,6 +2140,8 @@ impl fmt::Display for BlueprintDiffDisplay<'_, '_> { writeln!(f, "{}", table)?; } + // TODO-K: Add blocked updates in a follow up PR + Ok(()) } } diff --git a/nexus/types/src/deployment/planning_report.rs b/nexus/types/src/deployment/planning_report.rs index c69368da03f..92b1fafeabd 100644 --- a/nexus/types/src/deployment/planning_report.rs +++ b/nexus/types/src/deployment/planning_report.rs @@ -10,10 +10,16 @@ use super::BlueprintZoneImageSource; use super::CockroachDbPreserveDowngrade; use super::PendingMgsUpdates; use super::PlannerConfig; +use crate::deployment::MgsUpdateComponent; +use crate::inventory::BaseboardId; +use crate::inventory::CabooseWhich; use daft::Diffable; +use iddqd::IdOrdItem; +use iddqd::id_upcast; use indent_write::fmt::IndentWriter; use omicron_common::api::external::Generation; +use omicron_common::disk::M2Slot; use omicron_common::policy::COCKROACHDB_REDUNDANCY; use omicron_uuid_kinds::MupdateOverrideUuid; use omicron_uuid_kinds::OmicronZoneUuid; @@ -23,11 +29,12 @@ use omicron_uuid_kinds::ZpoolUuid; use schemars::JsonSchema; use serde::Deserialize; use serde::Serialize; - use std::collections::BTreeMap; use std::collections::BTreeSet; use std::fmt; use std::fmt::Write; +use std::sync::Arc; +use thiserror::Error; /// A full blueprint planning report. Other than the blueprint ID, each /// field corresponds to a step in the update planner, i.e., a subroutine @@ -71,9 +78,7 @@ impl PlanningReport { expunge: PlanningExpungeStepReport::new(), decommission: PlanningDecommissionStepReport::new(), noop_image_source: PlanningNoopImageSourceStepReport::new(), - mgs_updates: PlanningMgsUpdatesStepReport::new( - PendingMgsUpdates::new(), - ), + mgs_updates: PlanningMgsUpdatesStepReport::empty(), add: PlanningAddStepReport::new(), zone_updates: PlanningZoneUpdatesStepReport::new(), nexus_generation_bump: PlanningNexusGenerationBumpReport::new(), @@ -465,26 +470,128 @@ impl PlanningMupdateOverrideStepReport { } } +/// Describes the reason why an SP component failed to update +#[derive( + Error, + Debug, + Deserialize, + Serialize, + PartialEq, + Eq, + Diffable, + PartialOrd, + JsonSchema, + Ord, + Clone, +)] +#[serde(rename_all = "snake_case")] +#[serde(tag = "type", content = "value")] +// TODO-K: Separate into enums for each component as suggested in +// https://github.com/oxidecomputer/omicron/pull/9001#discussion_r2372863166 +// and including more detailed information as suggested in +// https://github.com/oxidecomputer/omicron/pull/9001#discussion_r2372842378 +pub enum FailedMgsUpdateReason { + /// The active host phase 1 slot does not match the boot disk + #[error("active phase 1 slot {0:?} does not match boot disk")] + ActiveHostPhase1SlotBootDiskMismatch(M2Slot), + /// The active host phase 1 hash was not found in inventory + #[error("active host phase 1 hash for slot {0:?} is not in inventory")] + ActiveHostPhase1HashNotInInventory(M2Slot), + /// The active host phase 1 slot was not found in inventory + #[error("active host phase 1 slot is not in inventory")] + ActiveHostPhase1SlotNotInInventory, + /// The component's caboose was missing a value for "sign" + #[error("caboose for {0:?} is missing sign")] + CabooseMissingSign(CabooseWhich), + /// The component's caboose was not found in the inventory + #[error("caboose for {0:?} is not in inventory")] + CabooseNotInInventory(CabooseWhich), + /// The version in the caboose or artifact was not able to be parsed + #[error("version from caboose {caboose:?} could not be parsed: {err}")] + FailedVersionParse { caboose: CabooseWhich, err: String }, + /// The inactive host phase 1 hash was not found in inventory + #[error("inactive host phase 1 hash for slot {0:?} is not in inventory")] + InactiveHostPhase1HashNotInInventory(M2Slot), + /// Last reconciliation details were not found in inventory + #[error("sled agent last reconciliation is not in inventory")] + LastReconciliationNotInInventory, + /// No artifact with the required conditions for the component was found + #[error("no matching artifact was found")] + NoMatchingArtifactFound, + /// RoT state was not found in inventory + #[error("rot state is not in inventory")] + RotStateNotInInventory, + /// Sled agent info was not found in inventory + #[error("sled agent info is not in inventory")] + SledAgentInfoNotInInventory, + /// The component's corresponding SP was not found in the inventory + #[error("corresponding SP is not in inventory")] + SpNotInInventory, + /// Too many artifacts with the required conditions for the component were + /// found + #[error("too many matching artifacts were found")] + TooManyMatchingArtifacts, + /// The sled agent reported an error determining the boot disk + #[error("sled agent was unable to determine the boot disk: {0:?}")] + UnableToDetermineBootDisk(String), + /// The sled agent reported an error retrieving boot disk phase 2 image + /// details + #[error("sled agent was unable to retrieve boot disk phase 2 image: {0:?}")] + UnableToRetrieveBootDiskPhase2Image(String), +} + +#[derive( + Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Diffable, JsonSchema, +)] +pub struct BlockedMgsUpdate { + /// id of the baseboard that we attempted to update + pub baseboard_id: Arc, + /// type of SP component that we attempted to update + pub component: MgsUpdateComponent, + /// reason why the update failed + pub reason: FailedMgsUpdateReason, +} + +impl IdOrdItem for BlockedMgsUpdate { + type Key<'a> = &'a BaseboardId; + fn key(&self) -> Self::Key<'_> { + &*self.baseboard_id + } + id_upcast!(); +} + #[derive( Clone, Debug, Deserialize, Serialize, PartialEq, Eq, Diffable, JsonSchema, )] pub struct PlanningMgsUpdatesStepReport { pub pending_mgs_updates: PendingMgsUpdates, + pub blocked_mgs_updates: Vec, } impl PlanningMgsUpdatesStepReport { - pub fn new(pending_mgs_updates: PendingMgsUpdates) -> Self { - Self { pending_mgs_updates } + pub fn new( + pending_mgs_updates: PendingMgsUpdates, + blocked_mgs_updates: Vec, + ) -> Self { + Self { pending_mgs_updates, blocked_mgs_updates } + } + + pub fn empty() -> Self { + Self { + pending_mgs_updates: PendingMgsUpdates::new(), + blocked_mgs_updates: Vec::new(), + } } pub fn is_empty(&self) -> bool { self.pending_mgs_updates.is_empty() + && self.blocked_mgs_updates.is_empty() } } impl fmt::Display for PlanningMgsUpdatesStepReport { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let Self { pending_mgs_updates } = self; + let Self { pending_mgs_updates, blocked_mgs_updates } = self; if !pending_mgs_updates.is_empty() { let n = pending_mgs_updates.len(); let s = plural(n); @@ -497,6 +604,18 @@ impl fmt::Display for PlanningMgsUpdatesStepReport { )?; } } + if !blocked_mgs_updates.is_empty() { + let n = blocked_mgs_updates.len(); + let s = plural(n); + writeln!(f, "* {n} blocked MGS update{s}:")?; + for update in blocked_mgs_updates { + writeln!( + f, + " * {} {}: {}", + update.baseboard_id, update.component, update.reason + )?; + } + } Ok(()) } } @@ -1035,13 +1154,16 @@ impl fmt::Display for PlanningZoneUpdatesStepReport { )] #[serde(rename_all = "snake_case", tag = "type")] pub enum ZoneUpdatesWaitingOn { + /// Waiting on blocked updates to RoT bootloader / RoT / SP / Host OS. + BlockedMgsUpdates, + /// Waiting on discretionary zone placement. DiscretionaryZones, /// Waiting on zones to propagate to inventory. InventoryPropagation, - /// Waiting on updates to RoT / SP / Host OS / etc. + /// Waiting on updates to RoT bootloader / RoT / SP / Host OS. PendingMgsUpdates, /// Waiting on the same set of blockers zone adds are waiting on. @@ -1051,10 +1173,13 @@ pub enum ZoneUpdatesWaitingOn { impl ZoneUpdatesWaitingOn { pub fn as_str(&self) -> &'static str { match self { + Self::BlockedMgsUpdates => { + "blocked MGS updates (RoT bootloader / RoT / SP / Host OS)" + } Self::DiscretionaryZones => "discretionary zones", Self::InventoryPropagation => "zone propagation to inventory", Self::PendingMgsUpdates => { - "pending MGS updates (RoT / SP / Host OS / etc.)" + "pending MGS updates (RoT bootloader / RoT / SP / Host OS)" } Self::ZoneAddBlockers => "zone add blockers", } diff --git a/nexus/types/src/inventory.rs b/nexus/types/src/inventory.rs index 7ca78f007ea..4ce66f8450b 100644 --- a/nexus/types/src/inventory.rs +++ b/nexus/types/src/inventory.rs @@ -469,7 +469,9 @@ pub struct HostPhase1FlashHash { Ord, Deserialize, Serialize, + JsonSchema, )] +#[serde(rename_all = "snake_case")] pub enum CabooseWhich { SpSlot0, SpSlot1, diff --git a/openapi/nexus-internal.json b/openapi/nexus-internal.json index c88486f9442..d1dfb00fa43 100644 --- a/openapi/nexus-internal.json +++ b/openapi/nexus-internal.json @@ -1161,6 +1161,40 @@ "port" ] }, + "BlockedMgsUpdate": { + "type": "object", + "properties": { + "baseboard_id": { + "description": "id of the baseboard that we attempted to update", + "allOf": [ + { + "$ref": "#/components/schemas/BaseboardId" + } + ] + }, + "component": { + "description": "type of SP component that we attempted to update", + "allOf": [ + { + "$ref": "#/components/schemas/MgsUpdateComponent" + } + ] + }, + "reason": { + "description": "reason why the update failed", + "allOf": [ + { + "$ref": "#/components/schemas/FailedMgsUpdateReason" + } + ] + } + }, + "required": [ + "baseboard_id", + "component", + "reason" + ] + }, "Blueprint": { "description": "Describes a complete set of software and configuration for the system", "type": "object", @@ -2215,6 +2249,18 @@ "format": "uint64", "minimum": 0 }, + "CabooseWhich": { + "description": "Describes which caboose this is (which component, which slot)", + "type": "string", + "enum": [ + "sp_slot0", + "sp_slot1", + "rot_slot_a", + "rot_slot_b", + "stage0", + "stage0_next" + ] + }, "Certificate": { "type": "object", "properties": { @@ -3177,6 +3223,280 @@ } ] }, + "FailedMgsUpdateReason": { + "description": "Describes the reason why an SP component failed to update", + "oneOf": [ + { + "description": "The active host phase 1 slot does not match the boot disk", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "active_host_phase1_slot_boot_disk_mismatch" + ] + }, + "value": { + "$ref": "#/components/schemas/M2Slot" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The active host phase 1 hash was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "active_host_phase1_hash_not_in_inventory" + ] + }, + "value": { + "$ref": "#/components/schemas/M2Slot" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The active host phase 1 slot was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "active_host_phase1_slot_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "The component's caboose was missing a value for \"sign\"", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "caboose_missing_sign" + ] + }, + "value": { + "$ref": "#/components/schemas/CabooseWhich" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The component's caboose was not found in the inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "caboose_not_in_inventory" + ] + }, + "value": { + "$ref": "#/components/schemas/CabooseWhich" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The version in the caboose or artifact was not able to be parsed", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "failed_version_parse" + ] + }, + "value": { + "type": "object", + "properties": { + "caboose": { + "$ref": "#/components/schemas/CabooseWhich" + }, + "err": { + "type": "string" + } + }, + "required": [ + "caboose", + "err" + ] + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The inactive host phase 1 hash was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "inactive_host_phase1_hash_not_in_inventory" + ] + }, + "value": { + "$ref": "#/components/schemas/M2Slot" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "Last reconciliation details were not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "last_reconciliation_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "No artifact with the required conditions for the component was found", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "no_matching_artifact_found" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "RoT state was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "rot_state_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Sled agent info was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "sled_agent_info_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "The component's corresponding SP was not found in the inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "sp_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Too many artifacts with the required conditions for the component were found", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "too_many_matching_artifacts" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "The sled agent reported an error determining the boot disk", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unable_to_determine_boot_disk" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The sled agent reported an error retrieving boot disk phase 2 image details", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unable_to_retrieve_boot_disk_phase2_image" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, "Generation": { "description": "Generation numbers stored in the database, used for optimistic concurrency control", "type": "integer", @@ -3436,6 +3756,15 @@ "minLength": 5, "maxLength": 17 }, + "MgsUpdateComponent": { + "type": "string", + "enum": [ + "sp", + "rot", + "rot_bootloader", + "host_os" + ] + }, "MigrationRuntimeState": { "description": "An update from a sled regarding the state of a migration, indicating the role of the VMM whose migration state was updated.", "type": "object", @@ -4382,11 +4711,18 @@ "PlanningMgsUpdatesStepReport": { "type": "object", "properties": { + "blocked_mgs_updates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlockedMgsUpdate" + } + }, "pending_mgs_updates": { "$ref": "#/components/schemas/PendingMgsUpdates" } }, "required": [ + "blocked_mgs_updates", "pending_mgs_updates" ] }, @@ -6003,6 +6339,21 @@ }, "ZoneUpdatesWaitingOn": { "oneOf": [ + { + "description": "Waiting on blocked updates to RoT bootloader / RoT / SP / Host OS.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "blocked_mgs_updates" + ] + } + }, + "required": [ + "type" + ] + }, { "description": "Waiting on discretionary zone placement.", "type": "object", @@ -6034,7 +6385,7 @@ ] }, { - "description": "Waiting on updates to RoT / SP / Host OS / etc.", + "description": "Waiting on updates to RoT bootloader / RoT / SP / Host OS.", "type": "object", "properties": { "type": { diff --git a/openapi/nexus-lockstep.json b/openapi/nexus-lockstep.json index a03852f4d5a..07d590a5efc 100644 --- a/openapi/nexus-lockstep.json +++ b/openapi/nexus-lockstep.json @@ -1476,6 +1476,40 @@ "serial_number" ] }, + "BlockedMgsUpdate": { + "type": "object", + "properties": { + "baseboard_id": { + "description": "id of the baseboard that we attempted to update", + "allOf": [ + { + "$ref": "#/components/schemas/BaseboardId" + } + ] + }, + "component": { + "description": "type of SP component that we attempted to update", + "allOf": [ + { + "$ref": "#/components/schemas/MgsUpdateComponent" + } + ] + }, + "reason": { + "description": "reason why the update failed", + "allOf": [ + { + "$ref": "#/components/schemas/FailedMgsUpdateReason" + } + ] + } + }, + "required": [ + "baseboard_id", + "component", + "reason" + ] + }, "Blueprint": { "description": "Describes a complete set of software and configuration for the system", "type": "object", @@ -2696,6 +2730,18 @@ "format": "uint64", "minimum": 0 }, + "CabooseWhich": { + "description": "Describes which caboose this is (which component, which slot)", + "type": "string", + "enum": [ + "sp_slot0", + "sp_slot1", + "rot_slot_a", + "rot_slot_b", + "stage0", + "stage0_next" + ] + }, "ClickhouseClusterConfig": { "description": "Global configuration for all clickhouse servers (replicas) and keepers", "type": "object", @@ -3415,6 +3461,280 @@ } ] }, + "FailedMgsUpdateReason": { + "description": "Describes the reason why an SP component failed to update", + "oneOf": [ + { + "description": "The active host phase 1 slot does not match the boot disk", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "active_host_phase1_slot_boot_disk_mismatch" + ] + }, + "value": { + "$ref": "#/components/schemas/M2Slot" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The active host phase 1 hash was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "active_host_phase1_hash_not_in_inventory" + ] + }, + "value": { + "$ref": "#/components/schemas/M2Slot" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The active host phase 1 slot was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "active_host_phase1_slot_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "The component's caboose was missing a value for \"sign\"", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "caboose_missing_sign" + ] + }, + "value": { + "$ref": "#/components/schemas/CabooseWhich" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The component's caboose was not found in the inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "caboose_not_in_inventory" + ] + }, + "value": { + "$ref": "#/components/schemas/CabooseWhich" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The version in the caboose or artifact was not able to be parsed", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "failed_version_parse" + ] + }, + "value": { + "type": "object", + "properties": { + "caboose": { + "$ref": "#/components/schemas/CabooseWhich" + }, + "err": { + "type": "string" + } + }, + "required": [ + "caboose", + "err" + ] + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The inactive host phase 1 hash was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "inactive_host_phase1_hash_not_in_inventory" + ] + }, + "value": { + "$ref": "#/components/schemas/M2Slot" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "Last reconciliation details were not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "last_reconciliation_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "No artifact with the required conditions for the component was found", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "no_matching_artifact_found" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "RoT state was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "rot_state_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Sled agent info was not found in inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "sled_agent_info_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "The component's corresponding SP was not found in the inventory", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "sp_not_in_inventory" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "Too many artifacts with the required conditions for the component were found", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "too_many_matching_artifacts" + ] + } + }, + "required": [ + "type" + ] + }, + { + "description": "The sled agent reported an error determining the boot disk", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unable_to_determine_boot_disk" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "value" + ] + }, + { + "description": "The sled agent reported an error retrieving boot disk phase 2 image details", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "unable_to_retrieve_boot_disk_phase2_image" + ] + }, + "value": { + "type": "string" + } + }, + "required": [ + "type", + "value" + ] + } + ] + }, "Generation": { "description": "Generation numbers stored in the database, used for optimistic concurrency control", "type": "integer", @@ -4037,6 +4357,15 @@ "sp" ] }, + "MgsUpdateComponent": { + "type": "string", + "enum": [ + "sp", + "rot", + "rot_bootloader", + "host_os" + ] + }, "MgsUpdateDriverStatus": { "description": "Status of ongoing update attempts, recently completed attempts, and update requests that are waiting for retry.", "type": "object", @@ -5222,6 +5551,10 @@ "$ref": "#/components/schemas/PlanningAddSufficientZonesExist" } }, + "target_release_generation_is_one": { + "description": "Set to true if the target release generation is 1, which would allow zones to be added.", + "type": "boolean" + }, "waiting_on": { "nullable": true, "description": "What are we waiting on to start zone additions?", @@ -5243,7 +5576,8 @@ "sleds_waiting_for_ntp_zone", "sleds_without_ntp_zones_in_inventory", "sleds_without_zpools_for_ntp_zones", - "sufficient_zones_exist" + "sufficient_zones_exist", + "target_release_generation_is_one" ] }, "PlanningAddSufficientZonesExist": { @@ -5310,11 +5644,18 @@ "PlanningMgsUpdatesStepReport": { "type": "object", "properties": { + "blocked_mgs_updates": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlockedMgsUpdate" + } + }, "pending_mgs_updates": { "$ref": "#/components/schemas/PendingMgsUpdates" } }, "required": [ + "blocked_mgs_updates", "pending_mgs_updates" ] }, @@ -7072,6 +7413,21 @@ }, "ZoneUpdatesWaitingOn": { "oneOf": [ + { + "description": "Waiting on blocked updates to RoT bootloader / RoT / SP / Host OS.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "blocked_mgs_updates" + ] + } + }, + "required": [ + "type" + ] + }, { "description": "Waiting on discretionary zone placement.", "type": "object", @@ -7103,7 +7459,7 @@ ] }, { - "description": "Waiting on updates to RoT / SP / Host OS / etc.", + "description": "Waiting on updates to RoT bootloader / RoT / SP / Host OS.", "type": "object", "properties": { "type": {