@@ -8,12 +8,12 @@ use super::DataStore;
88use crate :: authz;
99use crate :: context:: OpContext ;
1010use crate :: db:: error:: { public_error_from_diesel, ErrorHandler } ;
11- use crate :: db:: model:: { TargetRelease , TargetReleaseSource } ;
11+ use crate :: db:: model:: { SemverVersion , TargetRelease , TargetReleaseSource } ;
1212use crate :: db:: schema:: target_release:: dsl;
13- use crate :: transaction_retry:: OptionalError ;
1413use async_bb8_diesel:: AsyncRunQueryDsl as _;
1514use diesel:: insert_into;
1615use diesel:: prelude:: * ;
16+ use nexus_types:: external_api:: shared;
1717use omicron_common:: api:: external:: { CreateResult , LookupResult } ;
1818
1919impl DataStore {
@@ -29,12 +29,12 @@ impl DataStore {
2929 // Fetch the row in the `target_release` table with the largest
3030 // generation number. The subquery accesses the same table, so we
3131 // have to make an alias to not confuse diesel.
32- let target_release2 = diesel:: alias!(
32+ let target_release_2 = diesel:: alias!(
3333 crate :: db:: schema:: target_release as target_release_2
3434 ) ;
3535 dsl:: target_release
36- . filter ( dsl:: generation. nullable ( ) . eq_any ( target_release2 . select (
37- diesel:: dsl:: max ( target_release2 . field ( dsl:: generation) ) ,
36+ . filter ( dsl:: generation. nullable ( ) . eq_any ( target_release_2 . select (
37+ diesel:: dsl:: max ( target_release_2 . field ( dsl:: generation) ) ,
3838 ) ) )
3939 . select ( TargetRelease :: as_select ( ) )
4040 . first_async ( & * conn)
@@ -52,32 +52,10 @@ impl DataStore {
5252 ) -> CreateResult < TargetRelease > {
5353 opctx. authorize ( authz:: Action :: Modify , & authz:: FLEET ) . await ?;
5454 let conn = self . pool_connection_authorized ( opctx) . await ?;
55- let err = OptionalError :: new ( ) ;
5655 self . transaction_retry_wrapper ( "set_target_release" )
5756 . transaction ( & conn, |conn| {
5857 let target_release = target_release. clone ( ) ;
59- let err = err. clone ( ) ;
6058 async move {
61- // Ensure that we have a TUF repo representing a system version.
62- if let TargetReleaseSource :: SystemVersion =
63- target_release. release_source
64- {
65- if let Some ( system_version) =
66- target_release. system_version . clone ( )
67- {
68- assert_eq ! (
69- system_version. clone( ) ,
70- self . update_tuf_repo_get( opctx, system_version)
71- . await
72- . map_err( |e| err. bail( e) ) ?
73- . repo
74- . system_version,
75- "inconsistent system version"
76- ) ;
77- }
78- }
79-
80- // Insert the target_release row.
8159 insert_into ( dsl:: target_release)
8260 . values ( target_release)
8361 . returning ( TargetRelease :: as_returning ( ) )
@@ -86,13 +64,49 @@ impl DataStore {
8664 }
8765 } )
8866 . await
89- . map_err ( |e| {
90- if let Some ( err) = err. take ( ) {
91- err
92- } else {
93- public_error_from_diesel ( e, ErrorHandler :: Server )
67+ . map_err ( |e| public_error_from_diesel ( e, ErrorHandler :: Server ) )
68+ }
69+
70+ /// Convert a model-level target release to an external view.
71+ /// This method lives here because we have to look up the version
72+ /// corresponding to the TUF repo.
73+ pub async fn export_target_release (
74+ & self ,
75+ opctx : & OpContext ,
76+ target_release : & TargetRelease ,
77+ ) -> LookupResult < shared:: TargetRelease > {
78+ opctx. authorize ( authz:: Action :: Read , & authz:: FLEET ) . await ?;
79+ let conn = self . pool_connection_authorized ( opctx) . await ?;
80+ Ok ( shared:: TargetRelease {
81+ generation : ( & target_release. generation . 0 ) . into ( ) ,
82+ time_requested : target_release. time_requested ,
83+ release_source : match target_release. release_source {
84+ TargetReleaseSource :: Unspecified => {
85+ shared:: TargetReleaseSource :: Unspecified
9486 }
95- } )
87+ TargetReleaseSource :: SystemVersion => {
88+ use crate :: db:: schema:: tuf_repo;
89+ shared:: TargetReleaseSource :: SystemVersion (
90+ tuf_repo:: table
91+ . select ( tuf_repo:: system_version)
92+ . filter ( tuf_repo:: id. eq (
93+ target_release. tuf_repo_id . expect (
94+ "CONSTRAINT tuf_repo_for_system_version" ,
95+ ) ,
96+ ) )
97+ . first_async :: < SemverVersion > ( & * conn)
98+ . await
99+ . map_err ( |e| {
100+ public_error_from_diesel (
101+ e,
102+ ErrorHandler :: Server ,
103+ )
104+ } ) ?
105+ . into ( ) ,
106+ )
107+ }
108+ } ,
109+ } )
96110 }
97111}
98112
@@ -120,20 +134,20 @@ mod test {
120134 . get_target_release ( opctx)
121135 . await
122136 . expect ( "should be a target release" ) ;
123- assert_eq ! ( target_release. generation, Generation ( 0 . into( ) ) ) ;
137+ assert_eq ! ( target_release. generation, Generation ( 1 . into( ) ) ) ;
124138 assert ! ( target_release. time_requested < Utc :: now( ) ) ;
125139 assert_eq ! (
126140 target_release. release_source,
127- TargetReleaseSource :: InstallDataset
141+ TargetReleaseSource :: Unspecified
128142 ) ;
129- assert ! ( target_release. system_version . is_none( ) ) ;
143+ assert ! ( target_release. tuf_repo_id . is_none( ) ) ;
130144
131145 // We should be able to set a new generation just like the first,
132146 // with some (very small) fuzz allowed in the timestamp reported
133147 // by the database.
134148 let initial_target_release = TargetRelease :: new_from_prev (
135149 target_release,
136- TargetReleaseSource :: InstallDataset ,
150+ TargetReleaseSource :: Unspecified ,
137151 None ,
138152 ) ;
139153 let target_release = datastore
@@ -150,15 +164,15 @@ mod test {
150164 . abs( )
151165 < TimeDelta :: new( 0 , 1_000 ) . expect( "1 μsec" )
152166 ) ;
153- assert ! ( target_release. system_version . is_none( ) ) ;
167+ assert ! ( target_release. tuf_repo_id . is_none( ) ) ;
154168
155169 // Trying to reuse a generation should fail.
156170 assert ! ( datastore
157171 . set_target_release(
158172 opctx,
159173 TargetRelease :: new(
160174 target_release. generation,
161- TargetReleaseSource :: InstallDataset ,
175+ TargetReleaseSource :: Unspecified ,
162176 None ,
163177 )
164178 )
@@ -171,36 +185,21 @@ mod test {
171185 opctx,
172186 TargetRelease :: new_from_prev (
173187 target_release,
174- TargetReleaseSource :: InstallDataset ,
188+ TargetReleaseSource :: Unspecified ,
175189 None ,
176190 ) ,
177191 )
178192 . await
179193 . unwrap ( ) ;
180194
181- // If we specify a system version, it had better exist!
182- let _ = datastore
183- . set_target_release (
184- opctx,
185- TargetRelease :: new_from_prev (
186- target_release. clone ( ) ,
187- TargetReleaseSource :: SystemVersion ,
188- Some ( SemverVersion :: new ( 0 , 0 , 0 ) ) ,
189- ) ,
190- )
191- . await
192- . expect_err ( "unknown system version" ) ;
193-
194- // Finally, use a new generation number and a valid system version.
195- // We assume the queries above will have taken some non-trivial
196- // amount of time.
195+ // Finally, use a new generation number and a TUF repo source.
197196 let version = SemverVersion :: new ( 0 , 0 , 1 ) ;
198197 let hash = ArtifactHash (
199198 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
200199 . parse ( )
201200 . expect ( "SHA256('')" ) ,
202201 ) ;
203- let system_version = datastore
202+ let repo = datastore
204203 . update_tuf_repo_insert (
205204 opctx,
206205 TufRepoDescription {
@@ -225,31 +224,31 @@ mod test {
225224 . await
226225 . unwrap ( )
227226 . recorded
228- . repo
229- . system_version ;
230- assert_eq ! ( version, system_version) ;
227+ . repo ;
228+ assert_eq ! ( repo. system_version, version) ;
229+ let tuf_repo_id = repo. id ;
230+
231+ let before = Utc :: now ( ) ;
231232 let target_release = datastore
232233 . set_target_release (
233234 opctx,
234235 TargetRelease :: new_from_prev (
235236 target_release,
236237 TargetReleaseSource :: SystemVersion ,
237- Some ( version . clone ( ) ) ,
238+ Some ( tuf_repo_id ) ,
238239 ) ,
239240 )
240241 . await
241242 . unwrap ( ) ;
242- assert_eq ! ( target_release. generation, Generation ( 3 . into( ) ) ) ;
243- assert ! (
244- ( target_release. time_requested
245- - initial_target_release. time_requested)
246- > TimeDelta :: new( 0 , 1_000_000 ) . expect( "1 msec" )
247- ) ;
243+ let after = Utc :: now ( ) ;
244+ assert_eq ! ( target_release. generation, Generation ( 4 . into( ) ) ) ;
245+ assert ! ( target_release. time_requested >= before) ;
246+ assert ! ( target_release. time_requested <= after) ;
248247 assert_eq ! (
249248 target_release. release_source,
250249 TargetReleaseSource :: SystemVersion
251250 ) ;
252- assert_eq ! ( target_release. system_version , Some ( version ) ) ;
251+ assert_eq ! ( target_release. tuf_repo_id , Some ( tuf_repo_id ) ) ;
253252
254253 // Clean up.
255254 db. terminate ( ) . await ;
0 commit comments