5
5
use crate :: deployment:: PendingMgsUpdate ;
6
6
use crate :: deployment:: TargetReleaseDescription ;
7
7
use crate :: inventory:: BaseboardId ;
8
+ use crate :: inventory:: Caboose ;
9
+ use crate :: inventory:: CabooseWhich ;
10
+ use crate :: inventory:: Collection ;
8
11
use chrono:: DateTime ;
9
12
use chrono:: SecondsFormat ;
10
13
use chrono:: Utc ;
@@ -13,12 +16,12 @@ use futures::stream::StreamExt;
13
16
use iddqd:: IdOrdItem ;
14
17
use iddqd:: IdOrdMap ;
15
18
use iddqd:: id_upcast;
16
- use nexus_sled_agent_shared:: inventory:: ConfigReconcilerInventory ;
17
19
use nexus_sled_agent_shared:: inventory:: ConfigReconcilerInventoryResult ;
18
20
use nexus_sled_agent_shared:: inventory:: OmicronZoneImageSource ;
19
21
use nexus_sled_agent_shared:: inventory:: OmicronZoneType ;
20
22
use omicron_common:: api:: external:: MacAddr ;
21
23
use omicron_common:: api:: external:: ObjectStream ;
24
+ use omicron_common:: api:: external:: TufArtifactMeta ;
22
25
use omicron_common:: api:: external:: Vni ;
23
26
use omicron_common:: snake_case_result;
24
27
use omicron_common:: snake_case_result:: SnakeCaseResult ;
@@ -38,6 +41,7 @@ use std::time::Duration;
38
41
use std:: time:: Instant ;
39
42
use steno:: SagaResultErr ;
40
43
use steno:: UndoActionError ;
44
+ use tufaceous_artifact:: KnownArtifactKind ;
41
45
use uuid:: Uuid ;
42
46
43
47
pub async fn to_list < T , U > ( object_stream : ObjectStream < T > ) -> Vec < U >
@@ -520,22 +524,24 @@ impl IdOrdItem for WaitingStatus {
520
524
tag = "zone_status_version" ,
521
525
content = "details"
522
526
) ]
523
- pub enum ZoneStatusVersion {
527
+ pub enum TufRepoVersion {
524
528
Unknown ,
525
529
InstallDataset ,
526
530
Version ( Version ) ,
527
531
Error ( String ) ,
528
532
}
529
533
530
- impl Display for ZoneStatusVersion {
534
+ impl Display for TufRepoVersion {
531
535
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
532
536
match self {
533
- ZoneStatusVersion :: Unknown => write ! ( f, "unknown" ) ,
534
- ZoneStatusVersion :: InstallDataset => write ! ( f, "install dataset" ) ,
535
- ZoneStatusVersion :: Version ( version) => {
537
+ TufRepoVersion :: Unknown => write ! ( f, "unknown" ) ,
538
+ TufRepoVersion :: InstallDataset => {
539
+ write ! ( f, "install dataset" )
540
+ }
541
+ TufRepoVersion :: Version ( version) => {
536
542
write ! ( f, "{}" , version)
537
543
}
538
- ZoneStatusVersion :: Error ( s) => {
544
+ TufRepoVersion :: Error ( s) => {
539
545
write ! ( f, "{}" , s)
540
546
}
541
547
}
@@ -546,22 +552,32 @@ impl Display for ZoneStatusVersion {
546
552
pub struct ZoneStatus {
547
553
pub zone_id : OmicronZoneUuid ,
548
554
pub zone_type : OmicronZoneType ,
549
- pub version : ZoneStatusVersion ,
555
+ pub version : TufRepoVersion ,
556
+ }
557
+
558
+ #[ derive( Debug , Clone , PartialEq , Eq , Serialize , Deserialize , JsonSchema ) ]
559
+ pub struct SpStatus {
560
+ pub sled_id : Option < SledUuid > ,
561
+ pub slot0_version : TufRepoVersion ,
562
+ pub slot1_version : TufRepoVersion ,
550
563
}
551
564
552
565
#[ derive( Debug , Clone , Serialize , Deserialize , JsonSchema ) ]
553
566
pub struct UpdateStatus {
554
567
pub zones : BTreeMap < SledUuid , Vec < ZoneStatus > > ,
568
+ pub sps : BTreeMap < String , SpStatus > ,
555
569
}
556
570
557
571
impl UpdateStatus {
558
- pub fn new < ' a > (
572
+ pub fn new (
559
573
old : & TargetReleaseDescription ,
560
574
new : & TargetReleaseDescription ,
561
- sleds : impl Iterator <
562
- Item = ( & ' a SledUuid , & ' a Option < ConfigReconcilerInventory > ) ,
563
- > ,
575
+ inventory : & Collection ,
564
576
) -> UpdateStatus {
577
+ let sleds = inventory
578
+ . sled_agents
579
+ . iter ( )
580
+ . map ( |agent| ( & agent. sled_id , & agent. last_reconciliation ) ) ;
565
581
let zones = sleds
566
582
. map ( |( sled_id, inv) | {
567
583
(
@@ -583,40 +599,109 @@ impl UpdateStatus {
583
599
)
584
600
} )
585
601
. collect ( ) ;
586
- UpdateStatus { zones }
602
+ let baseboard_ids: Vec < _ > = inventory. sps . keys ( ) . cloned ( ) . collect ( ) ;
603
+
604
+ // Find all SP versions and git commits via cabooses
605
+ let mut sps: BTreeMap < BaseboardId , SpStatus > = baseboard_ids
606
+ . into_iter ( )
607
+ . map ( |baseboard_id| {
608
+ let slot0_version = inventory
609
+ . caboose_for ( CabooseWhich :: SpSlot0 , & baseboard_id)
610
+ . map_or ( TufRepoVersion :: Unknown , |c| {
611
+ Self :: caboose_to_version ( old, new, & c. caboose )
612
+ } ) ;
613
+ let slot1_version = inventory
614
+ . caboose_for ( CabooseWhich :: SpSlot1 , & baseboard_id)
615
+ . map_or ( TufRepoVersion :: Unknown , |c| {
616
+ Self :: caboose_to_version ( old, new, & c. caboose )
617
+ } ) ;
618
+ (
619
+ ( * baseboard_id) . clone ( ) ,
620
+ SpStatus { sled_id : None , slot0_version, slot1_version } ,
621
+ )
622
+ } )
623
+ . collect ( ) ;
624
+
625
+ // Fill in the sled_id for the sp if known
626
+ for sa in inventory. sled_agents . iter ( ) {
627
+ if let Some ( baseboard_id) = & sa. baseboard_id {
628
+ if let Some ( sp) = sps. get_mut ( baseboard_id) {
629
+ sp. sled_id = Some ( sa. sled_id ) ;
630
+ }
631
+ }
632
+ }
633
+
634
+ let sps = sps. into_iter ( ) . map ( |( k, v) | ( k. to_string ( ) , v) ) . collect ( ) ;
635
+
636
+ UpdateStatus { zones, sps }
637
+ }
638
+
639
+ fn caboose_to_version (
640
+ old : & TargetReleaseDescription ,
641
+ new : & TargetReleaseDescription ,
642
+ caboose : & Caboose ,
643
+ ) -> TufRepoVersion {
644
+ let matching_caboose = |a : & TufArtifactMeta | {
645
+ caboose. board == a. id . name
646
+ && matches ! (
647
+ a. id. kind. to_known( ) ,
648
+ Some (
649
+ KnownArtifactKind :: GimletSp
650
+ | KnownArtifactKind :: PscSp
651
+ | KnownArtifactKind :: SwitchSp
652
+ )
653
+ )
654
+ && caboose. version == a. id . version . to_string ( )
655
+ } ;
656
+ if let Some ( new) = new. tuf_repo ( ) {
657
+ if new. artifacts . iter ( ) . any ( matching_caboose) {
658
+ return TufRepoVersion :: Version (
659
+ new. repo . system_version . clone ( ) ,
660
+ ) ;
661
+ }
662
+ }
663
+ if let Some ( old) = old. tuf_repo ( ) {
664
+ if old. artifacts . iter ( ) . any ( matching_caboose) {
665
+ return TufRepoVersion :: Version (
666
+ old. repo . system_version . clone ( ) ,
667
+ ) ;
668
+ }
669
+ }
670
+
671
+ TufRepoVersion :: Unknown
587
672
}
588
673
589
- pub fn zone_image_source_to_version (
674
+ fn zone_image_source_to_version (
590
675
old : & TargetReleaseDescription ,
591
676
new : & TargetReleaseDescription ,
592
677
source : & OmicronZoneImageSource ,
593
678
res : & ConfigReconcilerInventoryResult ,
594
- ) -> ZoneStatusVersion {
679
+ ) -> TufRepoVersion {
595
680
if let ConfigReconcilerInventoryResult :: Err { message } = res {
596
- return ZoneStatusVersion :: Error ( message. clone ( ) ) ;
681
+ return TufRepoVersion :: Error ( message. clone ( ) ) ;
597
682
}
598
683
599
684
let & OmicronZoneImageSource :: Artifact { hash } = source else {
600
- return ZoneStatusVersion :: InstallDataset ;
685
+ return TufRepoVersion :: InstallDataset ;
601
686
} ;
602
687
603
688
if let Some ( old) = old. tuf_repo ( ) {
604
689
if old. artifacts . iter ( ) . any ( |meta| meta. hash == hash) {
605
- return ZoneStatusVersion :: Version (
690
+ return TufRepoVersion :: Version (
606
691
old. repo . system_version . clone ( ) ,
607
692
) ;
608
693
}
609
694
}
610
695
611
696
if let Some ( new) = new. tuf_repo ( ) {
612
697
if new. artifacts . iter ( ) . any ( |meta| meta. hash == hash) {
613
- return ZoneStatusVersion :: Version (
698
+ return TufRepoVersion :: Version (
614
699
new. repo . system_version . clone ( ) ,
615
700
) ;
616
701
}
617
702
}
618
703
619
- ZoneStatusVersion :: Unknown
704
+ TufRepoVersion :: Unknown
620
705
}
621
706
}
622
707
0 commit comments