@@ -12,8 +12,10 @@ use nexus_types::deployment::BlueprintPhysicalDiskDisposition;
12
12
use nexus_types:: deployment:: BlueprintSledConfig ;
13
13
use nexus_types:: deployment:: BlueprintZoneConfig ;
14
14
use nexus_types:: deployment:: BlueprintZoneDisposition ;
15
+ use nexus_types:: deployment:: BlueprintZoneImageSource ;
15
16
use nexus_types:: deployment:: BlueprintZoneType ;
16
17
use nexus_types:: deployment:: OmicronZoneExternalIp ;
18
+ use nexus_types:: deployment:: SledFilter ;
17
19
use nexus_types:: deployment:: blueprint_zone_type;
18
20
use omicron_common:: address:: DnsSubnet ;
19
21
use omicron_common:: address:: Ipv6Subnet ;
@@ -31,6 +33,7 @@ pub(crate) fn perform_all_blueprint_only_checks(blippy: &mut Blippy<'_>) {
31
33
check_external_networking ( blippy) ;
32
34
check_dataset_zpool_uniqueness ( blippy) ;
33
35
check_datasets ( blippy) ;
36
+ check_mupdate_override ( blippy) ;
34
37
}
35
38
36
39
fn check_underlay_ips ( blippy : & mut Blippy < ' _ > ) {
@@ -537,6 +540,55 @@ fn check_datasets(blippy: &mut Blippy<'_>) {
537
540
}
538
541
}
539
542
543
+ fn check_mupdate_override ( blippy : & mut Blippy < ' _ > ) {
544
+ // Perform checks for invariants that should be upheld if
545
+ // remove_mupdate_override is set for a sled.
546
+ for ( & sled_id, sled) in & blippy. blueprint ( ) . sleds {
547
+ if !sled. state . matches ( SledFilter :: InService ) {
548
+ continue ;
549
+ }
550
+
551
+ if let Some ( mupdate_override_id) = sled. remove_mupdate_override {
552
+ // All in-service zones should be set to InstallDataset.
553
+ for zone in & sled. zones {
554
+ if zone. disposition . is_in_service ( ) {
555
+ match & zone. image_source {
556
+ BlueprintZoneImageSource :: InstallDataset => {
557
+ // This is valid.
558
+ }
559
+ BlueprintZoneImageSource :: Artifact {
560
+ version,
561
+ hash,
562
+ } => {
563
+ // This is invalid -- if remove_mupdate_override is
564
+ // set, all zones must be InstallDataset.
565
+ blippy. push_sled_note (
566
+ sled_id,
567
+ Severity :: Fatal ,
568
+ SledKind :: MupdateOverrideWithArtifactZone {
569
+ mupdate_override_id,
570
+ zone : zone. clone ( ) ,
571
+ version : version. clone ( ) ,
572
+ hash : * hash,
573
+ } ,
574
+ ) ;
575
+ }
576
+ }
577
+ }
578
+ }
579
+
580
+ // TODO: The host phase 2 contents should be set to CurrentContents
581
+ // (waiting for
582
+ // https://github.com/oxidecomputer/omicron/issues/8542).
583
+
584
+ // TODO: PendingMgsUpdates for this sled should be empty. Mapping
585
+ // sled IDs to their MGS identifiers (baseboard ID) requires a map
586
+ // that's not currently part of the blueprint. We may want to either
587
+ // include that map in the blueprint, or pass it in via blippy.
588
+ }
589
+ }
590
+ }
591
+
540
592
#[ cfg( test) ]
541
593
mod tests {
542
594
use super :: * ;
@@ -545,10 +597,14 @@ mod tests {
545
597
use crate :: blippy:: Note ;
546
598
use nexus_reconfigurator_planning:: example:: ExampleSystemBuilder ;
547
599
use nexus_reconfigurator_planning:: example:: example;
600
+ use nexus_types:: deployment:: BlueprintZoneImageVersion ;
548
601
use nexus_types:: deployment:: BlueprintZoneType ;
549
602
use nexus_types:: deployment:: blueprint_zone_type;
550
603
use omicron_test_utils:: dev:: test_setup_log;
604
+ use omicron_uuid_kinds:: MupdateOverrideUuid ;
551
605
use std:: mem;
606
+ use tufaceous_artifact:: ArtifactHash ;
607
+ use tufaceous_artifact:: ArtifactVersion ;
552
608
553
609
// The tests below all take the example blueprint, mutate in some invalid
554
610
// way, and confirm that blippy reports the invalidity. This test confirms
@@ -1561,4 +1617,61 @@ mod tests {
1561
1617
1562
1618
logctx. cleanup_successful ( ) ;
1563
1619
}
1620
+
1621
+ #[ test]
1622
+ fn test_mupdate_override_with_artifact_image_source ( ) {
1623
+ static TEST_NAME : & str =
1624
+ "test_remove_mupdate_override_with_artifact_image_source" ;
1625
+ let logctx = test_setup_log ( TEST_NAME ) ;
1626
+ let ( _, _, mut blueprint) = example ( & logctx. log , TEST_NAME ) ;
1627
+
1628
+ // Find a sled with zones and set remove_mupdate_override on it.
1629
+ let ( & sled_id, sled) = blueprint
1630
+ . sleds
1631
+ . iter_mut ( )
1632
+ . find ( |( _, config) | !config. zones . is_empty ( ) )
1633
+ . expect ( "at least one sled with zones" ) ;
1634
+
1635
+ // Set the remove_mupdate_override field on the sled.
1636
+ let mupdate_override_id = MupdateOverrideUuid :: max ( ) ;
1637
+ sled. remove_mupdate_override = Some ( mupdate_override_id) ;
1638
+
1639
+ // Find a zone and set it to use an artifact image source.
1640
+ let kind = {
1641
+ let mut zone = sled
1642
+ . zones
1643
+ . iter_mut ( )
1644
+ . find ( |z| z. disposition . is_in_service ( ) )
1645
+ . expect ( "at least one in-service zone" ) ;
1646
+
1647
+ let version = BlueprintZoneImageVersion :: Available {
1648
+ version : ArtifactVersion :: new_const ( "1.0.0" ) ,
1649
+ } ;
1650
+ let hash = ArtifactHash ( [ 1u8 ; 32 ] ) ;
1651
+ zone. image_source = BlueprintZoneImageSource :: Artifact {
1652
+ version : version. clone ( ) ,
1653
+ hash,
1654
+ } ;
1655
+
1656
+ SledKind :: MupdateOverrideWithArtifactZone {
1657
+ mupdate_override_id,
1658
+ zone : zone. clone ( ) ,
1659
+ version,
1660
+ hash,
1661
+ }
1662
+ } ;
1663
+
1664
+ let expected_note = Note {
1665
+ severity : Severity :: Fatal ,
1666
+ kind : Kind :: Sled { sled_id, kind } ,
1667
+ } ;
1668
+
1669
+ let report =
1670
+ Blippy :: new ( & blueprint) . into_report ( BlippyReportSortKey :: Kind ) ;
1671
+ eprintln ! ( "{}" , report. display( ) ) ;
1672
+ assert_eq ! ( report. notes( ) . len( ) , 1 , "exactly one note expected" ) ;
1673
+ assert_eq ! ( report. notes( ) [ 0 ] , expected_note) ;
1674
+
1675
+ logctx. cleanup_successful ( ) ;
1676
+ }
1564
1677
}
0 commit comments