@@ -9,8 +9,8 @@ use crate::inventory::ZoneType;
9
9
use crate :: omicron_zone_config:: { self , OmicronZoneNic } ;
10
10
use crate :: typed_uuid:: DbTypedUuid ;
11
11
use crate :: {
12
- ByteCount , Generation , MacAddr , Name , SledState , SqlU8 , SqlU16 , SqlU32 ,
13
- impl_enum_type, ipv6,
12
+ ArtifactHash , ByteCount , Generation , MacAddr , Name , SledState , SqlU8 ,
13
+ SqlU16 , SqlU32 , TufArtifact , impl_enum_type, ipv6,
14
14
} ;
15
15
use anyhow:: { Context , Result , anyhow, bail} ;
16
16
use chrono:: { DateTime , Utc } ;
@@ -24,7 +24,6 @@ use nexus_db_schema::schema::{
24
24
bp_sled_metadata, bp_target,
25
25
} ;
26
26
use nexus_sled_agent_shared:: inventory:: OmicronZoneDataset ;
27
- use nexus_types:: deployment:: BlueprintDatasetConfig ;
28
27
use nexus_types:: deployment:: BlueprintDatasetDisposition ;
29
28
use nexus_types:: deployment:: BlueprintPhysicalDiskConfig ;
30
29
use nexus_types:: deployment:: BlueprintPhysicalDiskDisposition ;
@@ -34,6 +33,9 @@ use nexus_types::deployment::BlueprintZoneDisposition;
34
33
use nexus_types:: deployment:: BlueprintZoneType ;
35
34
use nexus_types:: deployment:: ClickhouseClusterConfig ;
36
35
use nexus_types:: deployment:: CockroachDbPreserveDowngrade ;
36
+ use nexus_types:: deployment:: {
37
+ BlueprintDatasetConfig , BlueprintZoneImageVersion ,
38
+ } ;
37
39
use nexus_types:: deployment:: { BlueprintZoneImageSource , blueprint_zone_type} ;
38
40
use nexus_types:: deployment:: {
39
41
OmicronZoneExternalFloatingAddr , OmicronZoneExternalFloatingIp ,
@@ -449,6 +451,9 @@ pub struct BpOmicronZone {
449
451
450
452
pub external_ip_id : Option < DbTypedUuid < ExternalIpKind > > ,
451
453
pub filesystem_pool : DbTypedUuid < ZpoolKind > ,
454
+
455
+ pub image_source : DbBpZoneImageSource ,
456
+ pub image_artifact_sha256 : Option < ArtifactHash > ,
452
457
}
453
458
454
459
impl BpOmicronZone {
@@ -468,6 +473,9 @@ impl BpOmicronZone {
468
473
expunged_ready_for_cleanup : disposition_expunged_ready_for_cleanup,
469
474
} = blueprint_zone. disposition . into ( ) ;
470
475
476
+ let DbBpZoneImageSourceColumns { image_source, image_artifact_data } =
477
+ blueprint_zone. image_source . clone ( ) . into ( ) ;
478
+
471
479
// Create a dummy record to start, then fill in the rest
472
480
let mut bp_omicron_zone = BpOmicronZone {
473
481
// Fill in the known fields that don't require inspecting
@@ -481,6 +489,11 @@ impl BpOmicronZone {
481
489
disposition_expunged_as_of_generation,
482
490
disposition_expunged_ready_for_cleanup,
483
491
zone_type : blueprint_zone. zone_type . kind ( ) . into ( ) ,
492
+ image_source,
493
+ // The version is not preserved here -- instead, it is looked up
494
+ // from the tuf_artifact table.
495
+ image_artifact_sha256 : image_artifact_data
496
+ . map ( |( _version, hash) | hash) ,
484
497
485
498
// Set the remainder of the fields to a default
486
499
primary_service_ip : "::1"
@@ -685,6 +698,7 @@ impl BpOmicronZone {
685
698
pub fn into_blueprint_zone_config (
686
699
self ,
687
700
nic_row : Option < BpOmicronZoneNic > ,
701
+ image_artifact_row : Option < TufArtifact > ,
688
702
) -> anyhow:: Result < BlueprintZoneConfig > {
689
703
// Build up a set of common fields for our `BlueprintZoneType`s
690
704
//
@@ -871,14 +885,20 @@ impl BpOmicronZone {
871
885
. disposition_expunged_ready_for_cleanup ,
872
886
} ;
873
887
888
+ let image_source_cols = DbBpZoneImageSourceColumns :: new (
889
+ self . image_source ,
890
+ self . image_artifact_sha256 ,
891
+ image_artifact_row,
892
+ ) ;
893
+
874
894
Ok ( BlueprintZoneConfig {
875
895
disposition : disposition_cols. try_into ( ) ?,
876
896
id : self . id . into ( ) ,
877
897
filesystem_pool : ZpoolName :: new_external (
878
898
self . filesystem_pool . into ( ) ,
879
899
) ,
880
900
zone_type,
881
- image_source : BlueprintZoneImageSource :: InstallDataset ,
901
+ image_source : image_source_cols . try_into ( ) ? ,
882
902
} )
883
903
}
884
904
}
@@ -958,6 +978,93 @@ impl TryFrom<DbBpZoneDispositionColumns> for BlueprintZoneDisposition {
958
978
}
959
979
}
960
980
981
+ impl_enum_type ! (
982
+ BpZoneImageSourceEnum :
983
+
984
+ #[ derive( Clone , Copy , Debug , AsExpression , FromSqlRow , PartialEq ) ]
985
+ pub enum DbBpZoneImageSource ;
986
+
987
+ // Enum values
988
+ InstallDataset => b"install_dataset"
989
+ Artifact => b"artifact"
990
+ ) ;
991
+
992
+ struct DbBpZoneImageSourceColumns {
993
+ image_source : DbBpZoneImageSource ,
994
+ // image_artifact_data is Some if and only if image_source is Artifact.
995
+ //
996
+ // The BlueprintZoneImageVersion is not actually stored in bp_omicron_zone
997
+ // table directly, but is instead looked up from the tuf_artifact table at
998
+ // blueprint load time.
999
+ image_artifact_data : Option < ( BlueprintZoneImageVersion , ArtifactHash ) > ,
1000
+ }
1001
+
1002
+ impl DbBpZoneImageSourceColumns {
1003
+ fn new (
1004
+ image_source : DbBpZoneImageSource ,
1005
+ image_artifact_sha256 : Option < ArtifactHash > ,
1006
+ image_artifact_row : Option < TufArtifact > ,
1007
+ ) -> Self {
1008
+ // Note that artifact_row can only be Some if image_artifact_sha256 is
1009
+ // Some.
1010
+ let image_artifact_data = image_artifact_sha256. map ( |hash| {
1011
+ let version = match image_artifact_row {
1012
+ Some ( artifact_row) => BlueprintZoneImageVersion :: Available {
1013
+ version : artifact_row. version . 0 ,
1014
+ } ,
1015
+ None => BlueprintZoneImageVersion :: Unknown ,
1016
+ } ;
1017
+ ( version, hash)
1018
+ } ) ;
1019
+ Self { image_source, image_artifact_data }
1020
+ }
1021
+ }
1022
+
1023
+ impl From < BlueprintZoneImageSource > for DbBpZoneImageSourceColumns {
1024
+ fn from ( image_source : BlueprintZoneImageSource ) -> Self {
1025
+ match image_source {
1026
+ BlueprintZoneImageSource :: InstallDataset => Self {
1027
+ image_source : DbBpZoneImageSource :: InstallDataset ,
1028
+ image_artifact_data : None ,
1029
+ } ,
1030
+ BlueprintZoneImageSource :: Artifact { version, hash } => Self {
1031
+ image_source : DbBpZoneImageSource :: Artifact ,
1032
+ image_artifact_data : Some ( ( version, hash. into ( ) ) ) ,
1033
+ } ,
1034
+ }
1035
+ }
1036
+ }
1037
+
1038
+ impl TryFrom < DbBpZoneImageSourceColumns > for BlueprintZoneImageSource {
1039
+ type Error = anyhow:: Error ;
1040
+
1041
+ fn try_from (
1042
+ value : DbBpZoneImageSourceColumns ,
1043
+ ) -> Result < Self , Self :: Error > {
1044
+ match ( value. image_source , value. image_artifact_data ) {
1045
+ ( DbBpZoneImageSource :: Artifact , Some ( ( version, hash) ) ) => {
1046
+ Ok ( Self :: Artifact { version, hash : hash. into ( ) } )
1047
+ }
1048
+ ( DbBpZoneImageSource :: Artifact , None ) => Err ( anyhow ! (
1049
+ "illegal database state (CHECK constraint broken?!): \
1050
+ image_source {:?}, image_artifact_data None",
1051
+ value. image_source,
1052
+ ) ) ,
1053
+ ( DbBpZoneImageSource :: InstallDataset , data @ Some ( _) ) => {
1054
+ Err ( anyhow ! (
1055
+ "illegal database state (CHECK constraint broken?!): \
1056
+ image_source {:?}, image_artifact_data {:?}",
1057
+ value. image_source,
1058
+ data,
1059
+ ) )
1060
+ }
1061
+ ( DbBpZoneImageSource :: InstallDataset , None ) => {
1062
+ Ok ( Self :: InstallDataset )
1063
+ }
1064
+ }
1065
+ }
1066
+ }
1067
+
961
1068
#[ derive( Queryable , Clone , Debug , Selectable , Insertable ) ]
962
1069
#[ diesel( table_name = bp_omicron_zone_nic) ]
963
1070
pub struct BpOmicronZoneNic {
0 commit comments