Skip to content

Commit 70edce7

Browse files
committed
Check zone image source in inventory
Also remove now-superfluous `OrderedComponent` enum.
1 parent b2f09a3 commit 70edce7

File tree

4 files changed

+45
-131
lines changed

4 files changed

+45
-131
lines changed

dev-tools/reconfigurator-cli/tests/output/cmds-expunge-newly-added-stdout

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -628,7 +628,7 @@ INFO sufficient InternalDns zones exist in plan, desired_count: 3, current_count
628628
INFO added zone to sled, sled_id: a88790de-5962-4871-8686-61c1fd5b7094, kind: ExternalDns
629629
INFO sufficient Nexus zones exist in plan, desired_count: 3, current_count: 3
630630
INFO sufficient Oximeter zones exist in plan, desired_count: 0, current_count: 0
631-
INFO zones not yet up-to-date, sled_id: a88790de-5962-4871-8686-61c1fd5b7094
631+
INFO some zones not yet up-to-date, sled_id: a88790de-5962-4871-8686-61c1fd5b7094
632632
INFO will ensure cockroachdb setting, setting: cluster.preserve_downgrade_option, value: DoNotModify
633633
generated blueprint 9c998c1d-1a7b-440a-ae0c-40f781dea6e2 based on parent blueprint 366b0b68-d80e-4bc1-abd3-dc69837847e0
634634

nexus/reconfigurator/planning/src/blueprint_builder/builder.rs

Lines changed: 18 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ use crate::blueprint_editor::ExternalSnatNetworkingChoice;
1414
use crate::blueprint_editor::NoAvailableDnsSubnets;
1515
use crate::blueprint_editor::SledEditError;
1616
use crate::blueprint_editor::SledEditor;
17-
use crate::planner::OrderedComponent;
1817
use crate::planner::ZoneExpungeReason;
1918
use crate::planner::rng::PlannerRng;
2019
use anyhow::Context as _;
@@ -1965,30 +1964,25 @@ impl<'a> BlueprintBuilder<'a> {
19651964
zone_kind: ZoneKind,
19661965
new_repo: Option<&TufRepoDescription>,
19671966
) -> bool {
1968-
match OrderedComponent::from(zone_kind) {
1969-
OrderedComponent::HostOs | OrderedComponent::SpRot => {
1970-
todo!("can't yet update Host OS or SP/RoT")
1971-
}
1972-
OrderedComponent::OmicronZone(kind) => match kind {
1973-
ZoneKind::Nexus => {
1974-
// Nexus can only be updated if all non-Nexus zones have been updated,
1975-
// i.e., their image source is an artifact from the new repo.
1976-
self.sled_ids_with_zones().all(|sled_id| {
1977-
self.current_sled_zones(
1978-
sled_id,
1979-
BlueprintZoneDisposition::is_in_service,
1980-
)
1981-
.filter(|z| z.zone_type.kind() != ZoneKind::Nexus)
1982-
.all(|z| {
1983-
z.image_source
1984-
== Self::zone_image_artifact(new_repo, z.kind())
1985-
})
1967+
match zone_kind {
1968+
ZoneKind::Nexus => {
1969+
// Nexus can only be updated if all non-Nexus zones have been updated,
1970+
// i.e., their image source is an artifact from the new repo.
1971+
self.sled_ids_with_zones().all(|sled_id| {
1972+
self.current_sled_zones(
1973+
sled_id,
1974+
BlueprintZoneDisposition::is_in_service,
1975+
)
1976+
.filter(|z| z.zone_type.kind() != ZoneKind::Nexus)
1977+
.all(|z| {
1978+
z.image_source
1979+
== Self::zone_image_artifact(new_repo, z.kind())
19861980
})
1987-
}
1988-
// <https://github.com/oxidecomputer/omicron/issues/6404>
1989-
// ZoneKind::CockroachDb => todo!("check cluster status in inventory"),
1990-
_ => true, // other zone kinds have no special dependencies
1991-
},
1981+
})
1982+
}
1983+
// <https://github.com/oxidecomputer/omicron/issues/6404>
1984+
// ZoneKind::CockroachDb => todo!("check cluster status in inventory"),
1985+
_ => true, // other zone kinds have no special dependencies
19921986
}
19931987
}
19941988

nexus/reconfigurator/planning/src/planner.rs

Lines changed: 26 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ use omicron_uuid_kinds::PhysicalDiskUuid;
3737
use omicron_uuid_kinds::SledUuid;
3838
use slog::error;
3939
use slog::{Logger, info, warn};
40+
use std::collections::BTreeMap;
4041
use std::collections::BTreeSet;
4142
use std::str::FromStr;
4243

@@ -45,11 +46,9 @@ use self::omicron_zone_placement::OmicronZonePlacement;
4546
use self::omicron_zone_placement::OmicronZonePlacementSledState;
4647
pub use self::rng::PlannerRng;
4748
pub use self::rng::SledPlannerRng;
48-
pub(crate) use self::update_sequence::OrderedComponent;
4949

5050
mod omicron_zone_placement;
5151
pub(crate) mod rng;
52-
mod update_sequence;
5352

5453
pub struct Planner<'a> {
5554
log: Logger,
@@ -905,34 +904,34 @@ impl<'a> Planner<'a> {
905904
.map(|(id, _details)| id)
906905
.collect::<Vec<_>>();
907906

908-
// Wait for all current zones to appear in the inventory.
909-
// TODO-correctness: We should check their image source,
910-
// but the inventory doesn't report that yet; see
911-
// <https://github.com/oxidecomputer/omicron/issues/8084>.
907+
// Wait for zones to appear up-to-date in the inventory.
912908
let inventory_zones = self
913909
.inventory
914-
.all_omicron_zones()
915-
.map(|z| z.id)
916-
.collect::<BTreeSet<_>>();
910+
.all_ledgered_omicron_zones()
911+
.map(|z| (z.id, z.image_source.clone()))
912+
.collect::<BTreeMap<_, _>>();
917913
for &sled_id in &sleds {
918914
if !self
919915
.blueprint
920916
.current_sled_zones(
921917
sled_id,
922918
BlueprintZoneDisposition::is_in_service,
923919
)
924-
.all(|zone| inventory_zones.contains(&zone.id))
920+
.all(|zone| {
921+
let image_source = zone.image_source.clone().into();
922+
inventory_zones.get(&zone.id) == Some(&image_source)
923+
})
925924
{
926925
info!(
927-
self.log, "zones not yet up-to-date";
926+
self.log, "some zones not yet up-to-date";
928927
"sled_id" => %sled_id,
929928
);
930929
return Ok(());
931930
}
932931
}
933932

934-
// Choose among the out-of-date zones one with the fewest dependencies.
935-
let mut out_of_date_zones = sleds
933+
// Update the first out-of-date zone.
934+
let out_of_date_zones = sleds
936935
.into_iter()
937936
.flat_map(|sled_id| {
938937
let blueprint = &self.blueprint;
@@ -949,8 +948,6 @@ impl<'a> Planner<'a> {
949948
})
950949
})
951950
.collect::<Vec<(SledUuid, BlueprintZoneConfig)>>();
952-
953-
sort_zones_by_deps(&mut out_of_date_zones);
954951
if let Some((sled_id, zone)) = out_of_date_zones.first() {
955952
return self.update_or_expunge_zone(*sled_id, zone);
956953
}
@@ -1113,15 +1110,6 @@ impl<'a> Planner<'a> {
11131110
}
11141111
}
11151112

1116-
/// Sort in place a vector of sled-specific zone configurations by API
1117-
/// dependencies (RFD 565 §6).
1118-
fn sort_zones_by_deps(zones: &mut Vec<(SledUuid, BlueprintZoneConfig)>) {
1119-
zones.sort_by(|a, b| {
1120-
OrderedComponent::from(a.1.zone_type.kind())
1121-
.cmp(&OrderedComponent::from(b.1.zone_type.kind()))
1122-
})
1123-
}
1124-
11251113
/// The reason a sled's zones need to be expunged.
11261114
///
11271115
/// This is used only for introspection and logging -- it's not part of the
@@ -4511,53 +4499,20 @@ pub(crate) mod test {
45114499
logctx.cleanup_successful();
45124500
}
45134501

4514-
#[test]
4515-
fn test_sort_zones_by_deps() {
4516-
static TEST_NAME: &str = "sort_zones_by_deps";
4517-
let logctx = test_setup_log(TEST_NAME);
4518-
let log = logctx.log.clone();
4519-
4520-
// Collect zone configs from our example system.
4521-
let (_collection, _input, blueprint) = example(&log, TEST_NAME);
4522-
let mut zones = blueprint
4523-
.all_omicron_zones(BlueprintZoneDisposition::any)
4524-
.map(|(sled_id, z)| (sled_id, z.clone()))
4525-
.collect::<Vec<(SledUuid, BlueprintZoneConfig)>>();
4526-
4527-
// Sort them and verify the ordering constraints.
4528-
sort_zones_by_deps(&mut zones);
4529-
let mut nexus = false;
4530-
for kind in zones.iter().map(|(_, z)| z.zone_type.kind()) {
4531-
match kind {
4532-
ZoneKind::Nexus => {
4533-
nexus = true;
4534-
}
4535-
_ => {
4536-
assert!(!nexus);
4537-
}
4538-
}
4539-
}
4540-
assert!(nexus);
4541-
4542-
logctx.cleanup_successful();
4543-
}
4544-
45454502
/// Manually update the example system's inventory collection's zones
45464503
/// from a blueprint.
45474504
fn update_collection_from_blueprint(
45484505
example: &mut ExampleSystem,
45494506
blueprint: &Blueprint,
45504507
) {
45514508
for (&sled_id, config) in blueprint.sleds.iter() {
4552-
let sled_config = config.clone().into_in_service_sled_config();
4553-
let zones_config = OmicronZonesConfig {
4554-
generation: sled_config.generation,
4555-
zones: sled_config.zones.into_iter().collect(),
4556-
};
45574509
example
45584510
.system
4559-
.sled_set_omicron_zones(sled_id, zones_config)
4560-
.expect("can't set omicron zones for sled");
4511+
.sled_set_omicron_config(
4512+
sled_id,
4513+
config.clone().into_in_service_sled_config(),
4514+
)
4515+
.expect("can't set sled config");
45614516
}
45624517
example.collection =
45634518
example.system.to_collection_builder().unwrap().build();
@@ -4787,33 +4742,20 @@ pub(crate) mod test {
47874742

47884743
parent = blueprint;
47894744
}
4745+
let blueprint9 = parent;
47904746

47914747
// All Crucible Pantries should now be updated.
47924748
assert_eq!(
4793-
parent
4749+
blueprint9
47944750
.all_omicron_zones(BlueprintZoneDisposition::is_in_service)
47954751
.filter(|(_, z)| is_up_to_date_pantry(z))
47964752
.count(),
47974753
CRUCIBLE_PANTRY_REDUNDANCY
47984754
);
47994755

4800-
// One more iteration for the last old zone to be expunged.
4801-
update_collection_from_blueprint(&mut example, &parent);
4802-
let blueprint10 = Planner::new_based_on(
4803-
log.clone(),
4804-
&parent,
4805-
&input,
4806-
"last_blueprint",
4807-
&example.collection,
4808-
)
4809-
.expect("can't create planner")
4810-
.with_rng(PlannerRng::from_seed((TEST_NAME, "last_bp")))
4811-
.plan()
4812-
.expect("replan for last blueprint");
4813-
48144756
// All old Pantry zones should now be expunged.
48154757
assert_eq!(
4816-
blueprint10
4758+
blueprint9
48174759
.all_omicron_zones(BlueprintZoneDisposition::is_expunged)
48184760
.filter(|(_, z)| is_old_pantry(z))
48194761
.count(),
@@ -4823,17 +4765,17 @@ pub(crate) mod test {
48234765
// Now we can update Nexus, because all of its dependent zones
48244766
// are up-to-date w/r/t the new repo.
48254767
assert_eq!(
4826-
parent
4768+
blueprint9
48274769
.all_omicron_zones(BlueprintZoneDisposition::is_in_service)
48284770
.filter(|(_, z)| is_old_nexus(z))
48294771
.count(),
48304772
NEXUS_REDUNDANCY + 1,
48314773
);
4832-
let mut parent = blueprint10;
4833-
for i in 11..=17 {
4834-
let blueprint_name = format!("blueprint_{i}");
4774+
let mut parent = blueprint9;
4775+
for i in 10..=17 {
48354776
update_collection_from_blueprint(&mut example, &parent);
48364777

4778+
let blueprint_name = format!("blueprint{i}");
48374779
let blueprint = Planner::new_based_on(
48384780
log.clone(),
48394781
&parent,
@@ -4847,7 +4789,6 @@ pub(crate) mod test {
48474789
.unwrap_or_else(|_| panic!("can't re-plan after {i} iterations"));
48484790

48494791
let summary = blueprint.diff_since_blueprint(&parent);
4850-
eprintln!("{}", summary.display());
48514792
for sled in summary.diff.sleds.modified_values_diff() {
48524793
if i % 2 == 0 {
48534794
assert!(sled.zones.added.is_empty());
@@ -4965,8 +4906,9 @@ pub(crate) mod test {
49654906

49664907
let mut parent = blueprint1;
49674908
for i in 2..=MAX_PLANNING_ITERATIONS {
4968-
let blueprint_name = format!("blueprint_{i}");
49694909
update_collection_from_blueprint(&mut example, &parent);
4910+
4911+
let blueprint_name = format!("blueprint{i}");
49704912
let blueprint = Planner::new_based_on(
49714913
log.clone(),
49724914
&parent,

nexus/reconfigurator/planning/src/planner/update_sequence.rs

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)