@@ -37,6 +37,7 @@ use omicron_uuid_kinds::PhysicalDiskUuid;
3737use omicron_uuid_kinds:: SledUuid ;
3838use slog:: error;
3939use slog:: { Logger , info, warn} ;
40+ use std:: collections:: BTreeMap ;
4041use std:: collections:: BTreeSet ;
4142use std:: str:: FromStr ;
4243
@@ -45,11 +46,9 @@ use self::omicron_zone_placement::OmicronZonePlacement;
4546use self :: omicron_zone_placement:: OmicronZonePlacementSledState ;
4647pub use self :: rng:: PlannerRng ;
4748pub use self :: rng:: SledPlannerRng ;
48- pub ( crate ) use self :: update_sequence:: OrderedComponent ;
4949
5050mod omicron_zone_placement;
5151pub ( crate ) mod rng;
52- mod update_sequence;
5352
5453pub 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,
0 commit comments