Skip to content

Commit 80f6902

Browse files
committed
InstallDataset → Unspecified, resolve tuf_repo_id
1 parent 307bd2a commit 80f6902

File tree

10 files changed

+133
-173
lines changed

10 files changed

+133
-173
lines changed

nexus/db-model/src/schema.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1417,7 +1417,7 @@ table! {
14171417
generation -> Int8,
14181418
time_requested -> Timestamptz,
14191419
release_source -> crate::TargetReleaseSourceEnum,
1420-
system_version -> Nullable<Text>,
1420+
tuf_repo_id -> Nullable<Uuid>,
14211421
}
14221422
}
14231423

nexus/db-model/src/target_release.rs

Lines changed: 9 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@
44

55
use super::{impl_enum_type, Generation};
66
use crate::schema::target_release;
7-
use crate::SemverVersion;
7+
use crate::typed_uuid::DbTypedUuid;
88
use chrono::{DateTime, Utc};
9-
use nexus_types::external_api::shared;
9+
use omicron_uuid_kinds::TufRepoKind;
1010

1111
impl_enum_type!(
1212
#[derive(SqlType, Debug, QueryId)]
@@ -18,7 +18,7 @@ impl_enum_type!(
1818
#[diesel(sql_type = TargetReleaseSourceEnum)]
1919
pub enum TargetReleaseSource;
2020

21-
InstallDataset => b"install_dataset"
21+
Unspecified => b"unspecified"
2222
SystemVersion => b"system_version"
2323
);
2424

@@ -37,52 +37,33 @@ pub struct TargetRelease {
3737
/// The source of the target release.
3838
pub release_source: TargetReleaseSource,
3939

40-
/// The semantic version of the target release.
41-
pub system_version: Option<SemverVersion>,
40+
/// The TUF repo containing the target release.
41+
pub tuf_repo_id: Option<DbTypedUuid<TufRepoKind>>,
4242
}
4343

4444
impl TargetRelease {
4545
pub fn new(
4646
generation: Generation,
4747
release_source: TargetReleaseSource,
48-
system_version: Option<SemverVersion>,
48+
tuf_repo_id: Option<DbTypedUuid<TufRepoKind>>,
4949
) -> Self {
5050
Self {
5151
generation,
5252
time_requested: Utc::now(),
5353
release_source,
54-
system_version,
54+
tuf_repo_id,
5555
}
5656
}
5757

5858
pub fn new_from_prev(
5959
prev: TargetRelease,
6060
release_source: TargetReleaseSource,
61-
system_version: Option<SemverVersion>,
61+
tuf_repo_id: Option<DbTypedUuid<TufRepoKind>>,
6262
) -> Self {
6363
Self::new(
6464
Generation(prev.generation.next()),
6565
release_source,
66-
system_version,
66+
tuf_repo_id,
6767
)
6868
}
69-
70-
pub fn into_external(self) -> shared::TargetRelease {
71-
shared::TargetRelease {
72-
generation: (&self.generation.0).into(),
73-
time_requested: self.time_requested,
74-
release_source: match self.release_source {
75-
TargetReleaseSource::InstallDataset => {
76-
shared::TargetReleaseSource::InstallDataset
77-
}
78-
TargetReleaseSource::SystemVersion => {
79-
shared::TargetReleaseSource::SystemVersion(
80-
self.system_version
81-
.expect("CONSTRAINT system_version_for_release")
82-
.into(),
83-
)
84-
}
85-
},
86-
}
87-
}
8869
}

nexus/db-queries/src/db/datastore/target_release.rs

Lines changed: 67 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,12 @@ use super::DataStore;
88
use crate::authz;
99
use crate::context::OpContext;
1010
use crate::db::error::{public_error_from_diesel, ErrorHandler};
11-
use crate::db::model::{TargetRelease, TargetReleaseSource};
11+
use crate::db::model::{SemverVersion, TargetRelease, TargetReleaseSource};
1212
use crate::db::schema::target_release::dsl;
13-
use crate::transaction_retry::OptionalError;
1413
use async_bb8_diesel::AsyncRunQueryDsl as _;
1514
use diesel::insert_into;
1615
use diesel::prelude::*;
16+
use nexus_types::external_api::shared;
1717
use omicron_common::api::external::{CreateResult, LookupResult};
1818

1919
impl 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

Comments
 (0)