From 01c30846f67f18b80501c2a91fe132e85471a05b Mon Sep 17 00:00:00 2001 From: iliana etaoin Date: Wed, 24 Sep 2025 12:46:59 -0700 Subject: [PATCH 1/3] semantic merge conflict due to nexus-lockstep move --- openapi/nexus-lockstep.json | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/openapi/nexus-lockstep.json b/openapi/nexus-lockstep.json index 8dbc8b3c484..a03852f4d5a 100644 --- a/openapi/nexus-lockstep.json +++ b/openapi/nexus-lockstep.json @@ -7087,6 +7087,21 @@ "type" ] }, + { + "description": "Waiting on zones to propagate to inventory.", + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": [ + "inventory_propagation" + ] + } + }, + "required": [ + "type" + ] + }, { "description": "Waiting on updates to RoT / SP / Host OS / etc.", "type": "object", From 36cd41d04edf78fdc23bfcbc15b5dc4a922b5400 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 24 Sep 2025 15:56:48 -0400 Subject: [PATCH 2/3] PlanningReport: Use JSON-safe map keys --- .../tests/output/cmds-target-release-stdout | 12 +++---- nexus/types/src/deployment/planning_report.rs | 34 +++++++------------ 2 files changed, 18 insertions(+), 28 deletions(-) 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..4eeec8d4ec8 100644 --- a/dev-tools/reconfigurator-cli/tests/output/cmds-target-release-stdout +++ b/dev-tools/reconfigurator-cli/tests/output/cmds-target-release-stdout @@ -7944,9 +7944,9 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 9 zones are already from artifacts * 3 remaining out-of-date zones * 3 zones waiting to be expunged: - * zone 0c71b3b2-6ceb-4e8f-b020-b08675e83038 (nexus): image out-of-date, but zone's nexus_generation 1 is still active - * zone 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6 (nexus): image out-of-date, but zone's nexus_generation 1 is still active - * zone 466a9f29-62bf-4e63-924a-b9efdb86afec (nexus): image out-of-date, but zone's nexus_generation 1 is still active + * zone 0c71b3b2-6ceb-4e8f-b020-b08675e83038: nexus image out-of-date, but nexus_generation 1 is still active + * zone 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6: nexus image out-of-date, but nexus_generation 1 is still active + * zone 466a9f29-62bf-4e63-924a-b9efdb86afec: nexus image out-of-date, but nexus_generation 1 is still active * updating top-level nexus_generation to: 2 @@ -8035,9 +8035,9 @@ planning report: * skipping noop zone image source check on sled d81c6a84-79b8-4958-ae41-ea46c9b19763: all 9 zones are already from artifacts * 3 remaining out-of-date zones * 3 zones waiting to be expunged: - * zone 0c71b3b2-6ceb-4e8f-b020-b08675e83038 (nexus): image out-of-date, but zone's nexus_generation 1 is still active - * zone 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6 (nexus): image out-of-date, but zone's nexus_generation 1 is still active - * zone 466a9f29-62bf-4e63-924a-b9efdb86afec (nexus): image out-of-date, but zone's nexus_generation 1 is still active + * zone 0c71b3b2-6ceb-4e8f-b020-b08675e83038: nexus image out-of-date, but nexus_generation 1 is still active + * zone 3eeb8d49-eb1a-43f8-bb64-c2338421c2c6: nexus image out-of-date, but nexus_generation 1 is still active + * zone 466a9f29-62bf-4e63-924a-b9efdb86afec: nexus image out-of-date, but nexus_generation 1 is still active diff --git a/nexus/types/src/deployment/planning_report.rs b/nexus/types/src/deployment/planning_report.rs index d4c9ac4c33a..ff7d6dd490b 100644 --- a/nexus/types/src/deployment/planning_report.rs +++ b/nexus/types/src/deployment/planning_report.rs @@ -833,8 +833,8 @@ pub struct PlanningZoneUpdatesStepReport { pub out_of_date_zones: BTreeMap>, pub expunged_zones: BTreeMap>, pub updated_zones: BTreeMap>, - pub unsafe_zones: BTreeMap, - pub waiting_zones: BTreeMap, + pub unsafe_zones: BTreeMap, + pub waiting_zones: BTreeMap, } impl PlanningZoneUpdatesStepReport { @@ -919,7 +919,7 @@ impl PlanningZoneUpdatesStepReport { zone: &BlueprintZoneConfig, reason: ZoneUnsafeToShutdown, ) { - self.unsafe_zones.insert(zone.clone(), reason); + self.unsafe_zones.insert(zone.id, reason); } pub fn waiting_zone( @@ -927,7 +927,7 @@ impl PlanningZoneUpdatesStepReport { zone: &BlueprintZoneConfig, reason: ZoneWaitingToExpunge, ) { - self.waiting_zones.insert(zone.clone(), reason); + self.waiting_zones.insert(zone.id, reason); } } @@ -986,28 +986,16 @@ impl fmt::Display for PlanningZoneUpdatesStepReport { if !unsafe_zones.is_empty() { let (n, s) = plural_map(unsafe_zones); writeln!(f, "* {n} zone{s} not ready to shut down safely:")?; - for (zone, reason) in unsafe_zones.iter() { - writeln!( - f, - " * zone {} ({}): {}", - zone.id, - zone.zone_type.kind().report_str(), - reason, - )?; + for (zone_id, reason) in unsafe_zones.iter() { + writeln!(f, " * zone {zone_id}: {reason}")?; } } if !waiting_zones.is_empty() { let (n, s) = plural_map(waiting_zones); writeln!(f, "* {n} zone{s} waiting to be expunged:")?; - for (zone, reason) in waiting_zones.iter() { - writeln!( - f, - " * zone {} ({}): {}", - zone.id, - zone.zone_type.kind().report_str(), - reason, - )?; + for (zone_id, reason) in waiting_zones.iter() { + writeln!(f, " * zone {zone_id}: {reason}")?; } } @@ -1061,7 +1049,9 @@ pub enum ZoneUnsafeToShutdown { impl fmt::Display for ZoneUnsafeToShutdown { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Self::Cockroachdb { reason } => write!(f, "{reason}"), + Self::Cockroachdb { reason } => { + write!(f, "cockroach unsafe to shut down: {reason}") + } Self::BoundaryNtp { total_boundary_ntp_zones: t, synchronized_count: s, @@ -1092,7 +1082,7 @@ impl fmt::Display for ZoneWaitingToExpunge { Self::Nexus { zone_generation } => { write!( f, - "image out-of-date, but zone's nexus_generation \ + "nexus image out-of-date, but nexus_generation \ {zone_generation} is still active" ) } From 25dabfc734184fe91bd3ae2ee9ef3860926817d8 Mon Sep 17 00:00:00 2001 From: John Gallagher Date: Wed, 24 Sep 2025 16:05:57 -0400 Subject: [PATCH 3/3] don't panic if planning report isn't valid JSON --- nexus/src/app/background/tasks/blueprint_planner.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/nexus/src/app/background/tasks/blueprint_planner.rs b/nexus/src/app/background/tasks/blueprint_planner.rs index b933ee55e8c..aaab2c90dfb 100644 --- a/nexus/src/app/background/tasks/blueprint_planner.rs +++ b/nexus/src/app/background/tasks/blueprint_planner.rs @@ -22,6 +22,7 @@ use omicron_common::api::external::LookupType; use omicron_uuid_kinds::CollectionUuid; use omicron_uuid_kinds::GenericUuid as _; use serde_json::json; +use slog_error_chain::InlineErrorChain; use std::sync::Arc; use tokio::sync::watch::{self, Receiver, Sender}; @@ -292,7 +293,16 @@ impl BackgroundTask for BlueprintPlanner { &'a mut self, opctx: &'a OpContext, ) -> BoxFuture<'a, serde_json::Value> { - Box::pin(async move { json!(self.plan(opctx).await) }) + Box::pin(async move { + let status = self.plan(opctx).await; + match serde_json::to_value(status) { + Ok(val) => val, + Err(err) => json!({ + "error": format!("could not serialize task status: {}", + InlineErrorChain::new(&err)), + }), + } + }) } }